| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 | 
							- //	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/thread.h>
 
- #include <wx/txtstrm.h>
 
- #include <zipper.hh>
 
- #include "ConfigUtil.hh"
 
- #include "TargetPanel.hh"
 
- #include "SCSI2SD_Bootloader.hh"
 
- #include "SCSI2SD_HID.hh"
 
- #include "Firmware.hh"
 
- #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
 
- #define MIN_FIRMWARE_VERSION 0x0400
 
- 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
 
- {
 
- static uint8_t sdCrc7(uint8_t* chr, uint8_t cnt, uint8_t crc)
 
- {
 
- 	uint8_t a;
 
- 	for(a = 0; a < cnt; a++)
 
- 	{
 
- 		uint8_t data = chr[a];
 
- 		uint8_t i;
 
- 		for(i = 0; i < 8; i++)
 
- 		{
 
- 			crc <<= 1;
 
- 			if ((data & 0x80) ^ (crc & 0x80))
 
- 			{
 
- 				crc ^= 0x09;
 
- 			}
 
- 			data <<= 1;
 
- 		}
 
- 	}
 
- 	return crc & 0x7F;
 
- }
 
- 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-util", wxPoint(50, 50), wxSize(600, 700)),
 
- 		myInitialConfig(false),
 
- 		myTickCounter(0),
 
- 		myLastPollTime(0)
 
- 	{
 
- 		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->AppendSeparator();
 
- 		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);
 
- 			for (int i = 0; i < MAX_SCSI_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, wxT("Load from device"));
 
- 			btnFgs->Add(myLoadButton);
 
- 			mySaveButton =
 
- 				new wxButton(btnPanel, ID_BtnSave, wxT("Save to device"));
 
- 			btnFgs->Add(mySaveButton);
 
- 			fgs->Add(btnPanel);
 
- 			btnPanel->Fit();
 
- 			cfgPanel->Fit();
 
- 		}
 
- 		//Fit(); // Needed to reduce window size on Windows
 
- 		FitInside(); // Needed on Linux to prevent status bar overlap
 
- 		myLogWindow = new wxLogWindow(this, wxT("scsi2sd-util debug log"), true);
 
- 		myLogWindow->PassMessages(false); // Prevent messagebox popups
 
- 		myTimer = new wxTimer(this, ID_Timer);
 
- 		myTimer->Start(16); //ms, suitable for scsi debug logging
 
- 	}
 
- private:
 
- 	wxLogWindow* myLogWindow;
 
- 	std::vector<TargetPanel*> myTargets;
 
- 	wxButton* myLoadButton;
 
- 	wxButton* mySaveButton;
 
- 	wxMenuItem* mySCSILogChk;
 
- 	wxMenuItem* mySelfTestChk;
 
- 	wxTimer* myTimer;
 
- 	shared_ptr<HID> myHID;
 
- 	shared_ptr<Bootloader> myBootloader;
 
- 	bool myInitialConfig;
 
- 	uint8_t myTickCounter;
 
- 	time_t myLastPollTime;
 
- 	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 &&
 
- 			(myHID->getFirmwareVersion() >= MIN_FIRMWARE_VERSION));
 
- 		myLoadButton->Enable(
 
- 			myHID &&
 
- 			(myHID->getFirmwareVersion() >= MIN_FIRMWARE_VERSION));
 
- 	}
 
- 	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
 
- 	};
 
- 	void OnID_ConfigDefaults(wxCommandEvent& event)
 
- 	{
 
- 		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";
 
- 		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::vector<TargetConfig> configs(
 
- 				ConfigUtil::fromXML(dlg.GetPath()));
 
- 			size_t i;
 
- 			for (i = 0; i < configs.size() && i < myTargets.size(); ++i)
 
- 			{
 
- 				myTargets[i]->setConfig(configs[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 (*.scsi2sd;*.cyacd)|*.cyacd;*.scsi2sd",
 
- 			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 (!myBootloader)
 
- 				{
 
- 					myBootloader.reset(Bootloader::Open());
 
- 					if (myBootloader)
 
- 					{
 
- 						mmLogStatus("Bootloader found");
 
- 						break;
 
- 					}
 
- 				}
 
- 				else if (myBootloader)
 
- 				{
 
- 					// Verify the USB HID connection is valid
 
- 					if (!myBootloader->ping())
 
- 					{
 
- 						mmLogStatus("Bootloader ping failed");
 
- 						myBootloader.reset();
 
- 					}
 
- 					else
 
- 					{
 
- 						mmLogStatus("Bootloader found");
 
- 						break;
 
- 					}
 
- 				}
 
- 			}
 
- 			catch (std::exception& e)
 
- 			{
 
- 				mmLogStatus(e.what());
 
- 				myHID.reset();
 
- 				myBootloader.reset();
 
- 			}
 
- 			wxMilliSleep(100);
 
- 			if (!progress->Pulse())
 
- 			{
 
- 				return; // user cancelled.
 
- 			}
 
- 		}
 
- 		int totalFlashRows = 0;
 
- 		std::string tmpFile;
 
- 		try
 
- 		{
 
- 			zipper::ReaderPtr reader(new zipper::FileReader(filename));
 
- 			zipper::Decompressor decomp(reader);
 
- 			std::vector<zipper::CompressedFilePtr> files(decomp.getEntries());
 
- 			for (auto it(files.begin()); it != files.end(); it++)
 
- 			{
 
- 				if (myBootloader->isCorrectFirmware((*it)->getPath()))
 
- 				{
 
- 					std::stringstream msg;
 
- 					msg << "Found firmware entry " << (*it)->getPath() <<
 
- 						" within archive " << filename;
 
- 					mmLogStatus(msg.str());
 
- 					tmpFile =
 
- 						wxFileName::CreateTempFileName(
 
- 							wxT("SCSI2SD_Firmware"), static_cast<wxFile*>(NULL)
 
- 							);
 
- 					zipper::FileWriter out(tmpFile);
 
- 					(*it)->decompress(out);
 
- 					msg.clear();
 
- 					msg << "Firmware extracted to " << tmpFile;
 
- 					mmLogStatus(msg.str());
 
- 					break;
 
- 				}
 
- 			}
 
- 			if (tmpFile.empty())
 
- 			{
 
- 				// TODO allow "force" option
 
- 				wxMessageBox(
 
- 					"Wrong filename",
 
- 					"Wrong filename",
 
- 					wxOK | wxICON_ERROR);
 
- 				return;
 
- 			}
 
- 			Firmware firmware(tmpFile);
 
- 			totalFlashRows = firmware.totalFlashRows();
 
- 		}
 
- 		catch (std::exception& e)
 
- 		{
 
- 			mmLogStatus(e.what());
 
- 			std::stringstream msg;
 
- 			msg << "Could not open firmware file: " << e.what();
 
- 			wxMessageBox(
 
- 				msg.str(),
 
- 				"Bad file",
 
- 				wxOK | wxICON_ERROR);
 
- 			wxRemoveFile(tmpFile);
 
- 			return;
 
- 		}
 
- 		{
 
- 			wxWindowPtr<wxGenericProgressDialog> progress(
 
- 				new wxGenericProgressDialog(
 
- 					"Loading firmware",
 
- 					"Loading firmware",
 
- 					totalFlashRows,
 
- 					this,
 
- 					wxPD_AUTO_HIDE | wxPD_REMAINING_TIME)
 
- 					);
 
- 			TheProgressWrapper.setProgressDialog(progress, totalFlashRows);
 
- 		}
 
- 		std::stringstream msg;
 
- 		msg << "Upgrading firmware from file: " << tmpFile;
 
- 		mmLogStatus(msg.str());
 
- 		try
 
- 		{
 
- 			myBootloader->load(tmpFile, &ProgressUpdate);
 
- 			TheProgressWrapper.clearProgressDialog();
 
- 			wxMessageBox(
 
- 				"Firmware update successful",
 
- 				"Firmware OK",
 
- 				wxOK);
 
- 			mmLogStatus("Firmware update successful");
 
- 			myHID.reset();
 
- 			myBootloader.reset();
 
- 		}
 
- 		catch (std::exception& e)
 
- 		{
 
- 			TheProgressWrapper.clearProgressDialog();
 
- 			mmLogStatus(e.what());
 
- 			myHID.reset();
 
- 			myBootloader.reset();
 
- 			wxMessageBox(
 
- 				"Firmware Update Failed",
 
- 				e.what(),
 
- 				wxOK | wxICON_ERROR);
 
- 			wxRemoveFile(tmpFile);
 
- 		}
 
- 	}
 
- 	void logSCSI()
 
- 	{
 
- 		if (!mySCSILogChk->IsChecked() ||
 
- 			!myHID)
 
- 		{
 
- 			return;
 
- 		}
 
- 		try
 
- 		{
 
- 			std::vector<uint8_t> info(HID::HID_PACKET_SIZE);
 
- 			if (myHID->readSCSIDebugInfo(info))
 
- 			{
 
- 				std::stringstream msg;
 
- 				msg << std::hex;
 
- 				for (size_t i = 0; i < 32 && i < info.size(); ++i)
 
- 				{
 
- 					msg << std::setfill('0') << std::setw(2) <<
 
- 						static_cast<int>(info[i]) << ' ';
 
- 				}
 
- 				wxLogMessage(this, msg.str().c_str());
 
- 			}
 
- 		}
 
- 		catch (std::exception& e)
 
- 		{
 
- 			wxLogWarning(this, e.what());
 
- 			myHID.reset();
 
- 		}
 
- 	}
 
- 	void OnID_Timer(wxTimerEvent& event)
 
- 	{
 
- 		logSCSI();
 
- 		time_t now = time(NULL);
 
- 		if (now == myLastPollTime) return;
 
- 		myLastPollTime = now;
 
- 		// Check if we are connected to the HID device.
 
- 		// AND/or bootloader device.
 
- 		try
 
- 		{
 
- 			if (myBootloader)
 
- 			{
 
- 				// Verify the USB HID connection is valid
 
- 				if (!myBootloader->ping())
 
- 				{
 
- 					myBootloader.reset();
 
- 				}
 
- 			}
 
- 			if (!myBootloader)
 
- 			{
 
- 				myBootloader.reset(Bootloader::Open());
 
- 				if (myBootloader)
 
- 				{
 
- 					mmLogStatus("SCSI2SD Bootloader Ready");
 
- 				}
 
- 			}
 
- 			int supressLog = 0;
 
- 			if (myHID && myHID->getFirmwareVersion() < MIN_FIRMWARE_VERSION)
 
- 			{
 
- 				// No method to check connection is still valid.
 
- 				// So assume it isn't.
 
- 				myHID.reset();
 
- 				supressLog = 1;
 
- 			}
 
- 			else if (myHID && !myHID->ping())
 
- 			{
 
- 				// Verify the USB HID connection is valid
 
- 				myHID.reset();
 
- 			}
 
- 			if (!myHID)
 
- 			{
 
- 				myHID.reset(HID::Open());
 
- 				if (myHID)
 
- 				{
 
- 					if (myHID->getFirmwareVersion() < MIN_FIRMWARE_VERSION)
 
- 					{
 
- 						if (!supressLog)
 
- 						{
 
- 							// Oh dear, old firmware
 
- 							std::stringstream msg;
 
- 							msg << "Firmware update required. Version " <<
 
- 								myHID->getFirmwareVersionStr();
 
- 							mmLogStatus(msg.str());
 
- 						}
 
- 					}
 
- 					else
 
- 					{
 
- 						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: ";
 
- 						if (sdCrc7(&csd[0], 15, 0) != (csd[15] >> 1))
 
- 						{
 
- 							sdinfo << "BADCRC ";
 
- 						}
 
- 						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: ";
 
- 						if (sdCrc7(&cid[0], 15, 0) != (cid[15] >> 1))
 
- 						{
 
- 							sdinfo << "BADCRC ";
 
- 						}
 
- 						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;
 
- 							scsiInfo << "SCSI Self-Test: " <<
 
- 								(myHID->scsiSelfTest() ? "Passed" : "FAIL");
 
- 							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 flashRow = SCSI_CONFIG_0_ROW;
 
- 		int currentProgress = 0;
 
- 		int totalProgress = myTargets.size() * SCSI_CONFIG_ROWS;
 
- 		for (size_t i = 0;
 
- 			i < myTargets.size();
 
- 			++i, flashRow += SCSI_CONFIG_ROWS)
 
- 		{
 
- 			std::vector<uint8_t> raw(sizeof(TargetConfig));
 
- 			for (size_t j = 0; j < SCSI_CONFIG_ROWS; ++j)
 
- 			{
 
- 				std::stringstream ss;
 
- 				ss << "Reading flash array " << SCSI_CONFIG_ARRAY <<
 
- 					" row " << (flashRow + j);
 
- 				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> flashData;
 
- 				try
 
- 				{
 
- 					myHID->readFlashRow(
 
- 						SCSI_CONFIG_ARRAY, flashRow + j, flashData);
 
- 				}
 
- 				catch (std::runtime_error& e)
 
- 				{
 
- 					mmLogStatus(e.what());
 
- 					goto err;
 
- 				}
 
- 				std::copy(
 
- 					flashData.begin(),
 
- 					flashData.end(),
 
- 					&raw[j * SCSI_CONFIG_ROW_SIZE]);
 
- 			}
 
- 			myTargets[i]->setConfig(ConfigUtil::fromBytes(&raw[0]));
 
- 		}
 
- 		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 flashRow = SCSI_CONFIG_0_ROW;
 
- 		int currentProgress = 0;
 
- 		int totalProgress = myTargets.size() * SCSI_CONFIG_ROWS;
 
- 		for (size_t i = 0;
 
- 			i < myTargets.size();
 
- 			++i, flashRow += SCSI_CONFIG_ROWS)
 
- 		{
 
- 			TargetConfig config(myTargets[i]->getConfig());
 
- 			std::vector<uint8_t> raw(ConfigUtil::toBytes(config));
 
- 			for (size_t j = 0; j < SCSI_CONFIG_ROWS; ++j)
 
- 			{
 
- 				std::stringstream ss;
 
- 				ss << "Programming flash array " << SCSI_CONFIG_ARRAY <<
 
- 					" row " << (flashRow + j);
 
- 				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;
 
- 				}
 
- 				std::vector<uint8_t> flashData(SCSI_CONFIG_ROW_SIZE, 0);
 
- 				std::copy(
 
- 					&raw[j * SCSI_CONFIG_ROW_SIZE],
 
- 					&raw[(1+j) * SCSI_CONFIG_ROW_SIZE],
 
- 					flashData.begin());
 
- 				try
 
- 				{
 
- 					myHID->writeFlashRow(
 
- 						SCSI_CONFIG_ARRAY, flashRow + j, flashData);
 
- 				}
 
- 				catch (std::runtime_error& e)
 
- 				{
 
- 					mmLogStatus(e.what());
 
- 					goto err;
 
- 				}
 
- 			}
 
- 		}
 
- 		// Reboot so new settings take effect.
 
- 		myHID->enterBootloader();
 
- 		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-util)\n"
 
- 			"Copyright (C) 2014 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-util", 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)
 
- 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();
 
- }
 
 
  |