| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020 | 
							- //	Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
 
- //
 
- //	This file is part of SCSI2SD.
 
- //
 
- //	SCSI2SD is free software: you can redistribute it and/or modify
 
- //	it under the terms of the GNU General Public License as published by
 
- //	the Free Software Foundation, either version 3 of the License, or
 
- //	(at your option) any later version.
 
- //
 
- //	SCSI2SD is distributed in the hope that it will be useful,
 
- //	but WITHOUT ANY WARRANTY; without even the implied warranty of
 
- //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
- //	GNU General Public License for more details.
 
- //
 
- //	You should have received a copy of the GNU General Public License
 
- //	along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
 
- // For compilers that support precompilation, includes "wx/wx.h".
 
- #include <wx/wxprec.h>
 
- #ifndef WX_PRECOMP
 
- #include <wx/wx.h>
 
- #endif
 
- #include <wx/app.h>
 
- #include <wx/filedlg.h>
 
- #include <wx/filefn.h>
 
- #include <wx/filename.h>
 
- #include <wx/log.h>
 
- #include <wx/notebook.h>
 
- #include <wx/progdlg.h>
 
- #include <wx/utils.h>
 
- #include <wx/wfstream.h>
 
- #include <wx/windowptr.h>
 
- #include <wx/stdpaths.h>
 
- #include <wx/stream.h>
 
- #include <wx/thread.h>
 
- #include <wx/txtstrm.h>
 
- #include <zipper.hh>
 
- #include "ConfigUtil.hh"
 
- #include "BoardPanel.hh"
 
- #include "TargetPanel.hh"
 
- #include "SCSI2SD_HID.hh"
 
- #include "Dfu.hh"
 
- #include "terminalwx.h"
 
- #include <algorithm>
 
- #include <iomanip>
 
- #include <vector>
 
- #include <set>
 
- #include <sstream>
 
- #if __cplusplus >= 201103L
 
- #include <cstdint>
 
- #include <memory>
 
- using std::shared_ptr;
 
- #else
 
- #include <stdint.h>
 
- #include <tr1/memory>
 
- using std::tr1::shared_ptr;
 
- #endif
 
- using namespace SCSI2SD;
 
- class ProgressWrapper
 
- {
 
- public:
 
- 	void setProgressDialog(
 
- 		const wxWindowPtr<wxGenericProgressDialog>& dlg,
 
- 		size_t maxRows)
 
- 	{
 
- 		myProgressDialog = dlg;
 
- 		myMaxRows = maxRows;
 
- 		myNumRows = 0;
 
- 	}
 
- 	void clearProgressDialog()
 
- 	{
 
- 		myProgressDialog->Show(false);
 
- 		myProgressDialog.reset();
 
- 	}
 
- 	void update(unsigned char arrayId, unsigned short rowNum)
 
- 	{
 
- 		if (!myProgressDialog) return;
 
- 		myNumRows++;
 
- 		std::stringstream ss;
 
- 		ss << "Writing flash array " <<
 
- 			static_cast<int>(arrayId) << " row " <<
 
- 			static_cast<int>(rowNum);
 
- 		wxLogMessage("%s", ss.str());
 
- 		myProgressDialog->Update(myNumRows, ss.str());
 
- 	}
 
- private:
 
- 	wxWindowPtr<wxGenericProgressDialog> myProgressDialog;
 
- 	size_t myMaxRows;
 
- 	size_t myNumRows;
 
- };
 
- static ProgressWrapper TheProgressWrapper;
 
- extern "C"
 
- void ProgressUpdate(unsigned char arrayId, unsigned short rowNum)
 
- {
 
- 	TheProgressWrapper.update(arrayId, rowNum);
 
- }
 
- namespace
 
- {
 
- class TimerLock
 
- {
 
- public:
 
- 	TimerLock(wxTimer* timer) :
 
- 		myTimer(timer),
 
- 		myInterval(myTimer->GetInterval())
 
- 	{
 
- 		myTimer->Stop();
 
- 	};
 
- 	virtual ~TimerLock()
 
- 	{
 
- 		if (myTimer && myInterval > 0)
 
- 		{
 
- 			myTimer->Start(myInterval);
 
- 		}
 
- 	}
 
- private:
 
- 	wxTimer* myTimer;
 
- 	int myInterval;
 
- };
 
- class AppFrame : public wxFrame
 
- {
 
- public:
 
- 	AppFrame() :
 
- 		wxFrame(NULL, wxID_ANY, "scsi2sd-util6", wxPoint(50, 50), wxSize(600, 700)),
 
- 		myInitialConfig(false),
 
- 		myTickCounter(0),
 
- 		myLastPollTime(0),
 
- 		myConsoleProcess(NULL)
 
- 	{
 
- 		wxMenu *menuFile = new wxMenu();
 
- 		menuFile->Append(
 
- 			ID_SaveFile,
 
- 			_("&Save to file..."),
 
- 			_("Save settings to local file."));
 
- 		menuFile->Append(
 
- 			ID_OpenFile,
 
- 			_("&Open file..."),
 
- 			_("Load settings from local file."));
 
- 		menuFile->AppendSeparator();
 
- 		menuFile->Append(
 
- 			ID_ConfigDefaults,
 
- 			_("Load &Defaults"),
 
- 			_("Load default configuration options."));
 
- 		menuFile->Append(
 
- 			ID_Firmware,
 
- 			_("&Upgrade Firmware..."),
 
- 			_("Upgrade or inspect device firmware version."));
 
- 		menuFile->Append(wxID_EXIT);
 
- 		wxMenu *menuWindow= new wxMenu();
 
- 		menuWindow->Append(
 
- 			ID_LogWindow,
 
- 			_("Show &Log"),
 
- 			_("Show debug log window"));
 
- 		wxMenu *menuDebug = new wxMenu();
 
- 		mySCSILogChk = menuDebug->AppendCheckItem(
 
- 			ID_SCSILog,
 
- 			_("Log SCSI data"),
 
- 			_("Log SCSI commands"));
 
- 		mySelfTestChk = menuDebug->AppendCheckItem(
 
- 			ID_SelfTest,
 
- 			_("SCSI Standalone Self-Test"),
 
- 			_("SCSI Standalone Self-Test"));
 
- 		wxMenu *menuHelp = new wxMenu();
 
- 		menuHelp->Append(wxID_ABOUT);
 
- 		wxMenuBar *menuBar = new wxMenuBar();
 
- 		menuBar->Append( menuFile, _("&File") );
 
- 		menuBar->Append( menuDebug, _("&Debug") );
 
- 		menuBar->Append( menuWindow, _("&Window") );
 
- 		menuBar->Append( menuHelp, _("&Help") );
 
- 		SetMenuBar( menuBar );
 
- 		CreateStatusBar();
 
- 		{
 
- 			wxPanel* cfgPanel = new wxPanel(this);
 
- 			wxFlexGridSizer *fgs = new wxFlexGridSizer(3, 1, 15, 15);
 
- 			cfgPanel->SetSizer(fgs);
 
- 			// Empty space below menu bar.
 
- 			fgs->Add(5, 5, wxALL);
 
- 			wxNotebook* tabs = new wxNotebook(cfgPanel, ID_Notebook);
 
- 			myBoardPanel = new BoardPanel(tabs, ConfigUtil::DefaultBoardConfig());
 
- 			tabs->AddPage(myBoardPanel, _("General Settings"));
 
- 			for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 
- 			{
 
- 				TargetPanel* target =
 
- 					new TargetPanel(tabs, ConfigUtil::Default(i));
 
- 				myTargets.push_back(target);
 
- 				std::stringstream ss;
 
- 				ss << "Device " << (i + 1);
 
- 				tabs->AddPage(target, ss.str());
 
- 				target->Fit();
 
- 			}
 
- 			tabs->Fit();
 
- 			fgs->Add(tabs);
 
- 			wxPanel* btnPanel = new wxPanel(cfgPanel);
 
- 			wxFlexGridSizer *btnFgs = new wxFlexGridSizer(1, 2, 5, 5);
 
- 			btnPanel->SetSizer(btnFgs);
 
- 			myLoadButton =
 
- 				new wxButton(btnPanel, ID_BtnLoad, _("Load from device"));
 
- 			btnFgs->Add(myLoadButton);
 
- 			mySaveButton =
 
- 				new wxButton(btnPanel, ID_BtnSave, _("Save to device"));
 
- 			btnFgs->Add(mySaveButton);
 
- 			fgs->Add(btnPanel);
 
- 			btnPanel->Fit();
 
- 			cfgPanel->Fit();
 
- 		}
 
- #ifdef __WINDOWS__
 
- 		Fit(); // Needed to reduce window size on Windows
 
- #else
 
- 		FitInside(); // Needed on Linux to prevent status bar overlap
 
- #endif
 
- 		myLogWindow = new wxLogWindow(this, _("scsi2sd-util6 debug log"), true);
 
- 		myLogWindow->PassMessages(false); // Prevent messagebox popups
 
- 		myTimer = new wxTimer(this, ID_Timer);
 
- 		myTimer->Start(64); //ms, suitable for scsi debug logging
 
- 	}
 
- private:
 
- 	Dfu myDfu;
 
- 	wxLogWindow* myLogWindow;
 
- 	BoardPanel* myBoardPanel;
 
- 	std::vector<TargetPanel*> myTargets;
 
- 	wxButton* myLoadButton;
 
- 	wxButton* mySaveButton;
 
- 	wxMenuItem* mySCSILogChk;
 
- 	wxMenuItem* mySelfTestChk;
 
- 	wxTimer* myTimer;
 
- 	shared_ptr<HID> myHID;
 
- 	bool myInitialConfig;
 
- 	uint8_t myTickCounter;
 
- 	time_t myLastPollTime;
 
- 	wxWindowPtr<TerminalWx> myConsoleTerm;
 
- 	shared_ptr<wxProcess> myConsoleProcess;
 
- 	wxInputStream* myConsoleStdout;
 
- 	wxInputStream* myConsoleStderr;
 
- 	
 
- 	void mmLogStatus(const std::string& msg)
 
- 	{
 
- 		// We set PassMessages to false on our log window to prevent popups, but
 
- 		// this also prevents wxLogStatus from updating the status bar.
 
- 		SetStatusText(msg);
 
- 		wxLogMessage(this, "%s", msg.c_str());
 
- 	}
 
- 	void onConfigChanged(wxCommandEvent& event)
 
- 	{
 
- 		evaluate();
 
- 	}
 
- 	void evaluate()
 
- 	{
 
- 		bool valid = true;
 
- 		// Check for duplicate SCSI IDs
 
- 		std::set<uint8_t> enabledID;
 
- 		// Check for overlapping SD sectors.
 
- 		std::vector<std::pair<uint32_t, uint64_t> > sdSectors;
 
- 		bool isTargetEnabled = false; // Need at least one enabled
 
- 		uint32_t autoStartSector = 0;
 
- 		for (size_t i = 0; i < myTargets.size(); ++i)
 
- 		{
 
- 			myTargets[i]->setAutoStartSector(autoStartSector);
 
- 			valid = myTargets[i]->evaluate() && valid;
 
- 			if (myTargets[i]->isEnabled())
 
- 			{
 
- 				isTargetEnabled = true;
 
- 				uint8_t scsiID = myTargets[i]->getSCSIId();
 
- 				if (enabledID.find(scsiID) != enabledID.end())
 
- 				{
 
- 					myTargets[i]->setDuplicateID(true);
 
- 					valid = false;
 
- 				}
 
- 				else
 
- 				{
 
- 					enabledID.insert(scsiID);
 
- 					myTargets[i]->setDuplicateID(false);
 
- 				}
 
- 				auto sdSectorRange = myTargets[i]->getSDSectorRange();
 
- 				for (auto it(sdSectors.begin()); it != sdSectors.end(); ++it)
 
- 				{
 
- 					if (sdSectorRange.first < it->second &&
 
- 						sdSectorRange.second > it->first)
 
- 					{
 
- 						valid = false;
 
- 						myTargets[i]->setSDSectorOverlap(true);
 
- 					}
 
- 					else
 
- 					{
 
- 						myTargets[i]->setSDSectorOverlap(false);
 
- 					}
 
- 				}
 
- 				sdSectors.push_back(sdSectorRange);
 
- 				autoStartSector = sdSectorRange.second;
 
- 			}
 
- 			else
 
- 			{
 
- 				myTargets[i]->setDuplicateID(false);
 
- 				myTargets[i]->setSDSectorOverlap(false);
 
- 			}
 
- 		}
 
- 		valid = valid && isTargetEnabled; // Need at least one.
 
- 		mySaveButton->Enable(valid && myHID);
 
- 		myLoadButton->Enable(static_cast<bool>(myHID));
 
- 	}
 
- 	enum
 
- 	{
 
- 		ID_ConfigDefaults = wxID_HIGHEST + 1,
 
- 		ID_Firmware,
 
- 		ID_Timer,
 
- 		ID_Notebook,
 
- 		ID_BtnLoad,
 
- 		ID_BtnSave,
 
- 		ID_LogWindow,
 
- 		ID_SCSILog,
 
- 		ID_SelfTest,
 
- 		ID_SaveFile,
 
- 		ID_OpenFile,
 
- 		ID_ConsoleTerm
 
- 	};
 
- 	void OnID_ConfigDefaults(wxCommandEvent& event)
 
- 	{
 
- 		myBoardPanel->setConfig(ConfigUtil::DefaultBoardConfig());
 
- 		for (size_t i = 0; i < myTargets.size(); ++i)
 
- 		{
 
- 			myTargets[i]->setConfig(ConfigUtil::Default(i));
 
- 		}
 
- 	}
 
- 	void OnID_SaveFile(wxCommandEvent& event)
 
- 	{
 
- 		TimerLock lock(myTimer);
 
- 		wxFileDialog dlg(
 
- 			this,
 
- 			"Save config settings",
 
- 			"",
 
- 			"",
 
- 			"XML files (*.xml)|*.xml",
 
- 			wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
- 		if (dlg.ShowModal() == wxID_CANCEL) return;
 
- 		wxFileOutputStream file(dlg.GetPath());
 
- 		if (!file.IsOk())
 
- 		{
 
- 			wxLogError("Cannot save settings to file '%s'.", dlg.GetPath());
 
- 			return;
 
- 		}
 
- 		wxTextOutputStream s(file);
 
- 		s << "<SCSI2SD>\n";
 
- 		s << ConfigUtil::toXML(myBoardPanel->getConfig());
 
- 		for (size_t i = 0; i < myTargets.size(); ++i)
 
- 		{
 
- 			s << ConfigUtil::toXML(myTargets[i]->getConfig());
 
- 		}
 
- 		s << "</SCSI2SD>\n";
 
- 	}
 
- 	void OnID_OpenFile(wxCommandEvent& event)
 
- 	{
 
- 		TimerLock lock(myTimer);
 
- 		wxFileDialog dlg(
 
- 			this,
 
- 			"Load config settings",
 
- 			"",
 
- 			"",
 
- 			"XML files (*.xml)|*.xml",
 
- 			wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 
- 		if (dlg.ShowModal() == wxID_CANCEL) return;
 
- 		try
 
- 		{
 
- 			std::pair<S2S_BoardCfg, std::vector<S2S_TargetCfg>> configs(
 
- 				ConfigUtil::fromXML(std::string(dlg.GetPath())));
 
- 			myBoardPanel->setConfig(configs.first);
 
- 			size_t i;
 
- 			for (i = 0; i < configs.second.size() && i < myTargets.size(); ++i)
 
- 			{
 
- 				myTargets[i]->setConfig(configs.second[i]);
 
- 			}
 
- 			for (; i < myTargets.size(); ++i)
 
- 			{
 
- 				myTargets[i]->setConfig(ConfigUtil::Default(i));
 
- 			}
 
- 		}
 
- 		catch (std::exception& e)
 
- 		{
 
- 			wxLogError(
 
- 				"Cannot load settings from file '%s'.\n%s",
 
- 				dlg.GetPath(),
 
- 				e.what());
 
- 			wxMessageBox(
 
- 				e.what(),
 
- 				"Load error",
 
- 				wxOK | wxICON_ERROR);
 
- 		}
 
- 	}
 
- 	void OnID_Firmware(wxCommandEvent& event)
 
- 	{
 
- 		TimerLock lock(myTimer);
 
- 		doFirmwareUpdate();
 
- 	}
 
- 	void OnID_LogWindow(wxCommandEvent& event)
 
- 	{
 
- 		myLogWindow->Show();
 
- 	}
 
- 	void doFirmwareUpdate()
 
- 	{
 
- 		wxFileDialog dlg(
 
- 			this,
 
- 			"Load firmware file",
 
- 			"",
 
- 			"",
 
- 			"SCSI2SD Firmware files (*.dfu)|*.dfu",
 
- 			wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 
- 		if (dlg.ShowModal() == wxID_CANCEL) return;
 
- 		std::string filename(dlg.GetPath());
 
- 		wxWindowPtr<wxGenericProgressDialog> progress(
 
- 			new wxGenericProgressDialog(
 
- 				"Searching for bootloader",
 
- 				"Searching for bootloader",
 
- 				100,
 
- 				this,
 
- 				wxPD_AUTO_HIDE | wxPD_CAN_ABORT)
 
- 				);
 
- 		mmLogStatus("Searching for bootloader");
 
- 		while (true)
 
- 		{
 
- 			try
 
- 			{
 
- 				if (!myHID) myHID.reset(HID::Open());
 
- 				if (myHID)
 
- 				{
 
- 					mmLogStatus("Resetting SCSI2SD into bootloader");
 
- 					myHID->enterBootloader();
 
- 					myHID.reset();
 
- 				}
 
- 				if (myDfu.hasDevice())
 
- 				{
 
- 					mmLogStatus("STM DFU Bootloader found");
 
- 					progress->Show(0);
 
- 					doDFUUpdate(filename);
 
- 					return;
 
- 				}
 
- 			}
 
- 			catch (std::exception& e)
 
- 			{
 
- 				mmLogStatus(e.what());
 
- 				myHID.reset();
 
- 			}
 
- 			wxMilliSleep(100);
 
- 			if (!progress->Pulse())
 
- 			{
 
- 				return; // user cancelled.
 
- 			}
 
- 		}
 
- 	}
 
- 	void doDFUUpdate(const std::string& filename)
 
- 	{
 
- 		if (filename.find(".dfu") == std::string::npos)
 
- 		{
 
- 			wxMessageBox(
 
- 				"Wrong filename",
 
- 				"SCSI2SD V6 requires a .dfu file",
 
- 				wxOK | wxICON_ERROR);
 
- 			return;
 
- 		}
 
- 		std::stringstream ss;
 
- #ifdef __WINDOWS__
 
- 		ss << "dfu-util --download \""
 
- 			<< filename.c_str() << "\" --alt 0 --reset";
 
- #else
 
- 		if (wxExecute("which dfu-util", wxEXEC_SYNC) == 0)
 
- 		{
 
- 			ss << "dfu-util ";
 
- 		} else {
 
- 			wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
 
- 			ss << '"' << exePath.GetPathWithSep() << "dfu-util\" ";
 
- 		}
 
- 		ss << "--download \"" << filename.c_str() << "\" --alt 0 --reset";
 
- #endif
 
- 		wxLogMessage("Running: %s", ss.str());
 
- 		myConsoleProcess.reset(new wxProcess(this));
 
- 		myConsoleProcess->Redirect();
 
- 		std::string cmd = ss.str();
 
- 		long result = wxExecute(
 
- 			cmd.c_str(),
 
- 			wxEXEC_ASYNC,
 
- 			myConsoleProcess.get()
 
- 			);
 
- 		if (!result)
 
- 		{
 
- 			wxMessageBox(
 
- 				"Update failed",
 
- 				"Firmware update failed (dfu-util not found ?) Command = " + cmd,
 
- 				wxOK | wxICON_ERROR);
 
- 			mmLogStatus("Firmware update failed");
 
- 			myConsoleProcess.reset();
 
- 		} else {
 
- 			myConsoleStdout = myConsoleProcess->GetInputStream();
 
- 			myConsoleStderr = myConsoleProcess->GetErrorStream();
 
- 			wxFrame* frame(new wxFrame(this, wxID_ANY, "dfu-util"));
 
- 			myConsoleTerm.reset(new TerminalWx(frame, wxID_ANY, wxDefaultPosition));
 
- 			frame->Fit();
 
- 			frame->Show();
 
- 		}
 
- 	}
 
- 	void redirectDfuOutput()
 
- 	{
 
- 		if (myConsoleProcess)
 
- 		{
 
- 			std::stringstream ss;
 
- 			while (myConsoleStderr && !myConsoleStderr->Eof() && myConsoleStderr->CanRead())
 
- 			{
 
- 				int c = myConsoleStderr->GetC();
 
- 				if (c == '\n')
 
- 				{
 
- 					ss << "\r\n";
 
- 				}
 
- 				else if (c >= 0)
 
- 				{
 
- 					ss << (char) c;
 
- 				}
 
- 			}
 
- 			while (myConsoleStdout && !myConsoleStdout->Eof() && myConsoleStdout->CanRead())
 
- 			{
 
- 				int c = myConsoleStdout->GetC();
 
- 				if (c == '\n')
 
- 				{
 
- 					ss << "\r\n";
 
- 				}
 
- 				else if (c >= 0)
 
- 				{
 
- 					ss << (char) c;
 
- 				}
 
- 			}
 
- 			myConsoleTerm->DisplayCharsUnsafe(ss.str());
 
- 		}
 
- 	}
 
- 	void doFinishDfu(wxProcessEvent& event)
 
- 	{
 
- 		redirectDfuOutput();
 
- 		if (event.GetExitCode() == 0)
 
- 		{
 
- 			wxMessageBox(
 
- 				"Update complete",
 
- 				"Firmware update complete. Please reconnect USB cable.",
 
- 				wxOK | wxICON_ERROR);
 
- 			mmLogStatus("Firmware update succeeded");
 
- 		} else {
 
- 			wxMessageBox(
 
- 				"Update failed",
 
- 				"Firmware update failed.",
 
- 				wxOK | wxICON_ERROR);
 
- 			mmLogStatus("Firmware update failed");
 
- 		}
 
- 		myConsoleStdout = myConsoleStderr = NULL;
 
- 		myConsoleProcess.reset();
 
- 		myConsoleTerm->GetParent()->Close();
 
- 		myConsoleTerm->Close();
 
- 		myConsoleTerm.reset();
 
- 	}
 
- 	void dumpSCSICommand(std::vector<uint8_t> buf)
 
-         {
 
- 		std::stringstream msg;
 
- 		msg << std::hex;
 
- 		for (size_t i = 0; i < 32 && i < buf.size(); ++i)
 
- 		{
 
- 			msg << std::setfill('0') << std::setw(2) <<
 
- 			static_cast<int>(buf[i]) << ' ';
 
- 		}
 
- 		wxLogMessage(this, msg.str().c_str());
 
-         }
 
- 	void logSCSI()
 
- 	{
 
- 		if (!mySCSILogChk->IsChecked() ||
 
- 			!myHID)
 
- 		{
 
- 			return;
 
- 		}
 
- 		try
 
- 		{
 
- 			std::vector<uint8_t> info;
 
- 			if (myHID->readSCSIDebugInfo(info))
 
- 			{
 
- 				dumpSCSICommand(info);
 
- 			}
 
- 		}
 
- 		catch (std::exception& e)
 
- 		{
 
- 			wxLogWarning(this, e.what());
 
- 			myHID.reset();
 
- 		}
 
- 	}
 
- 	void OnID_Timer(wxTimerEvent& event)
 
- 	{
 
- 		redirectDfuOutput();
 
- 		logSCSI();
 
- 		time_t now = time(NULL);
 
- 		if (now == myLastPollTime) return;
 
- 		myLastPollTime = now;
 
- 		// Check if we are connected to the HID device.
 
- 		try
 
- 		{
 
- 			if (myHID && !myHID->ping())
 
- 			{
 
- 				// Verify the USB HID connection is valid
 
- 				myHID.reset();
 
- 			}
 
- 			if (!myHID)
 
- 			{
 
- 				myHID.reset(HID::Open());
 
- 				if (myHID)
 
- 				{
 
- 					std::stringstream msg;
 
- 					msg << "SCSI2SD Ready, firmware version " <<
 
- 						myHID->getFirmwareVersionStr();
 
- 					mmLogStatus(msg.str());
 
- 					std::vector<uint8_t> csd(myHID->getSD_CSD());
 
- 					std::vector<uint8_t> cid(myHID->getSD_CID());
 
- 					std::stringstream sdinfo;
 
- 					sdinfo << "SD Capacity (512-byte sectors): " <<
 
- 						myHID->getSDCapacity() << std::endl;
 
- 					sdinfo << "SD CSD Register: ";
 
- 					for (size_t i = 0; i < csd.size(); ++i)
 
- 					{
 
- 						sdinfo <<
 
- 							std::hex << std::setfill('0') << std::setw(2) <<
 
- 							static_cast<int>(csd[i]);
 
- 					}
 
- 					sdinfo << std::endl;
 
- 					sdinfo << "SD CID Register: ";
 
- 					for (size_t i = 0; i < cid.size(); ++i)
 
- 					{
 
- 						sdinfo <<
 
- 							std::hex << std::setfill('0') << std::setw(2) <<
 
- 							static_cast<int>(cid[i]);
 
- 					}
 
- 					wxLogMessage(this, "%s", sdinfo.str());
 
- 					if (mySelfTestChk->IsChecked())
 
- 					{
 
- 						std::stringstream scsiInfo;
 
- 						int errcode;
 
- 						scsiInfo << "SCSI Self-Test: ";
 
- 						if (myHID->scsiSelfTest(errcode))
 
- 						{
 
- 							scsiInfo << "Passed";
 
- 						}
 
- 						else
 
- 						{
 
- 							scsiInfo << "FAIL (" << errcode << ")";
 
- 						}
 
- 						wxLogMessage(this, "%s", scsiInfo.str());
 
- 					}
 
- 					if (!myInitialConfig)
 
- 					{
 
- /* This doesn't work properly, and causes crashes.
 
- 						wxCommandEvent loadEvent(wxEVT_NULL, ID_BtnLoad);
 
- 						GetEventHandler()->AddPendingEvent(loadEvent);
 
- */
 
- 					}
 
- 				}
 
- 				else
 
- 				{
 
- 					char ticks[] = {'/', '-', '\\', '|'};
 
- 					std::stringstream ss;
 
- 					ss << "Searching for SCSI2SD device " << ticks[myTickCounter % sizeof(ticks)];
 
- 					myTickCounter++;
 
- 					SetStatusText(ss.str());
 
- 				}
 
- 			}
 
- 		}
 
- 		catch (std::runtime_error& e)
 
- 		{
 
- 			std::cerr << e.what() << std::endl;
 
- 			mmLogStatus(e.what());
 
- 		}
 
- 		evaluate();
 
- 	}
 
- 	void doLoad(wxCommandEvent& event)
 
- 	{
 
- 		TimerLock lock(myTimer);
 
- 		if (!myHID) return;
 
- 		mmLogStatus("Loading configuration");
 
- 		wxWindowPtr<wxGenericProgressDialog> progress(
 
- 			new wxGenericProgressDialog(
 
- 				"Load config settings",
 
- 				"Loading config settings",
 
- 				100,
 
- 				this,
 
- 				wxPD_CAN_ABORT | wxPD_REMAINING_TIME)
 
- 				);
 
- 		int currentProgress = 0;
 
- 		int totalProgress = 2;
 
- 		std::vector<uint8_t> cfgData(S2S_CFG_SIZE);
 
- 		uint32_t sector = myHID->getSDCapacity() - 2;
 
- 		for (size_t i = 0; i < 2; ++i)
 
- 		{
 
- 			std::stringstream ss;
 
- 			ss << "Reading sector " << sector;
 
- 			mmLogStatus(ss.str());
 
- 			currentProgress += 1;
 
- 			if (currentProgress == totalProgress)
 
- 			{
 
- 				ss.str("Load Complete.");
 
- 				mmLogStatus("Load Complete.");
 
- 			}
 
- 			if (!progress->Update(
 
- 					(100 * currentProgress) / totalProgress,
 
- 					ss.str()
 
- 					)
 
- 				)
 
- 			{
 
- 				goto abort;
 
- 			}
 
- 			std::vector<uint8_t> sdData;
 
- 			try
 
- 			{
 
- 				myHID->readSector(sector++, sdData);
 
- 			}
 
- 			catch (std::runtime_error& e)
 
- 			{
 
- 				mmLogStatus(e.what());
 
- 				goto err;
 
- 			}
 
- 			std::copy(
 
- 				sdData.begin(),
 
- 				sdData.end(),
 
- 				&cfgData[i * 512]);
 
- 		}
 
- 		myBoardPanel->setConfig(ConfigUtil::boardConfigFromBytes(&cfgData[0]));
 
- 		for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 
- 		{
 
- 			myTargets[i]->setConfig(
 
- 				ConfigUtil::fromBytes(
 
- 					&cfgData[sizeof(S2S_BoardCfg) + i * sizeof(S2S_TargetCfg)]
 
- 					)
 
- 				);
 
- 		}
 
- 		myInitialConfig = true;
 
- 		goto out;
 
- 	err:
 
- 		mmLogStatus("Load failed");
 
- 		progress->Update(100, "Load failed");
 
- 		goto out;
 
- 	abort:
 
- 		mmLogStatus("Load Aborted");
 
- 	out:
 
- 		return;
 
- 	}
 
- 	void doSave(wxCommandEvent& event)
 
- 	{
 
- 		TimerLock lock(myTimer);
 
- 		if (!myHID) return;
 
- 		mmLogStatus("Saving configuration");
 
- 		wxWindowPtr<wxGenericProgressDialog> progress(
 
- 			new wxGenericProgressDialog(
 
- 				"Save config settings",
 
- 				"Saving config settings",
 
- 				100,
 
- 				this,
 
- 				wxPD_CAN_ABORT | wxPD_REMAINING_TIME)
 
- 				);
 
- 		int currentProgress = 0;
 
- 		int totalProgress = 2;
 
- 		std::vector<uint8_t> cfgData(
 
- 			ConfigUtil::boardConfigToBytes(myBoardPanel->getConfig())
 
- 			);
 
- 		for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 
- 		{
 
- 			std::vector<uint8_t> raw(
 
- 				ConfigUtil::toBytes(myTargets[i]->getConfig())
 
- 				);
 
- 			cfgData.insert(cfgData.end(), raw.begin(), raw.end());
 
- 		}
 
- 		uint32_t sector = myHID->getSDCapacity() - 2;
 
- 		for (size_t i = 0; i < 2; ++i)
 
- 		{
 
- 			std::stringstream ss;
 
- 			ss << "Writing SD sector " << sector;
 
- 			mmLogStatus(ss.str());
 
- 			currentProgress += 1;
 
- 			if (currentProgress == totalProgress)
 
- 			{
 
- 				ss.str("Save Complete.");
 
- 				mmLogStatus("Save Complete.");
 
- 			}
 
- 			if (!progress->Update(
 
- 					(100 * currentProgress) / totalProgress,
 
- 					ss.str()
 
- 					)
 
- 				)
 
- 			{
 
- 				goto abort;
 
- 			}
 
- 			try
 
- 			{
 
- 				std::vector<uint8_t> buf;
 
- 				buf.insert(buf.end(), &cfgData[i * 512], &cfgData[(i+1) * 512]);
 
- 				myHID->writeSector(sector++, buf);
 
- 			}
 
- 			catch (std::runtime_error& e)
 
- 			{
 
- 				mmLogStatus(e.what());
 
- 				goto err;
 
- 			}
 
- 		}
 
- 		myHID.reset();
 
- 		goto out;
 
- 	err:
 
- 		mmLogStatus("Save failed");
 
- 		progress->Update(100, "Save failed");
 
- 		goto out;
 
- 	abort:
 
- 		mmLogStatus("Save Aborted");
 
- 	out:
 
- 		return;
 
- 	}
 
- 	// Note: Don't confuse this with the wxApp::OnExit virtual method
 
- 	void OnExitEvt(wxCommandEvent& event);
 
- 	void OnCloseEvt(wxCloseEvent& event);
 
- 	void OnAbout(wxCommandEvent& event)
 
- 	{
 
- 		wxMessageBox(
 
- 			"SCSI2SD (scsi2sd-util6)\n"
 
- 			"Copyright (C) 2014-2016 Michael McMaster <michael@codesrc.com>\n"
 
- 			"\n"
 
- "This program is free software: you can redistribute it and/or modify\n"
 
- "it under the terms of the GNU General Public License as published by\n"
 
- "the Free Software Foundation, either version 3 of the License, or\n"
 
- "(at your option) any later version.\n"
 
- "\n"
 
- "This program is distributed in the hope that it will be useful,\n"
 
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
 
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 
- "GNU General Public License for more details.\n"
 
- "\n"
 
- "You should have received a copy of the GNU General Public License\n"
 
- "along with this program.  If not, see <http://www.gnu.org/licenses/>.\n",
 
- 			"About scsi2sd-util6", wxOK | wxICON_INFORMATION );
 
- 	}
 
- 	wxDECLARE_EVENT_TABLE();
 
- };
 
- wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
 
- 	EVT_MENU(AppFrame::ID_ConfigDefaults, AppFrame::OnID_ConfigDefaults)
 
- 	EVT_MENU(AppFrame::ID_Firmware, AppFrame::OnID_Firmware)
 
- 	EVT_MENU(AppFrame::ID_LogWindow, AppFrame::OnID_LogWindow)
 
- 	EVT_MENU(AppFrame::ID_SaveFile, AppFrame::OnID_SaveFile)
 
- 	EVT_MENU(AppFrame::ID_OpenFile, AppFrame::OnID_OpenFile)
 
- 	EVT_MENU(wxID_EXIT, AppFrame::OnExitEvt)
 
- 	EVT_MENU(wxID_ABOUT, AppFrame::OnAbout)
 
- 	EVT_TIMER(AppFrame::ID_Timer, AppFrame::OnID_Timer)
 
- 	EVT_COMMAND(wxID_ANY, ConfigChangedEvent, AppFrame::onConfigChanged)
 
- 	EVT_BUTTON(ID_BtnSave, AppFrame::doSave)
 
- 	EVT_BUTTON(ID_BtnLoad, AppFrame::doLoad)
 
- 	EVT_CLOSE(AppFrame::OnCloseEvt)
 
- 	EVT_END_PROCESS(wxID_ANY, AppFrame::doFinishDfu)
 
- wxEND_EVENT_TABLE()
 
- class App : public wxApp
 
- {
 
- public:
 
- 	virtual bool OnInit()
 
- 	{
 
- 		AppFrame* frame = new AppFrame();
 
- 		frame->Show(true);
 
- 		SetTopWindow(frame);
 
- 		return true;
 
- 	}
 
- };
 
- } // namespace
 
- // Main Method
 
- wxIMPLEMENT_APP(App);
 
- void
 
- AppFrame::OnExitEvt(wxCommandEvent& event)
 
- {
 
- 	wxGetApp().ExitMainLoop();
 
- }
 
- void
 
- AppFrame::OnCloseEvt(wxCloseEvent& event)
 
- {
 
- 	wxGetApp().ExitMainLoop();
 
- }
 
 
  |