| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961 | 
							- //	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/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/windowptr.h>
 
- #include <wx/thread.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, 650)),
 
- 		myInitialConfig(false),
 
- 		myTickCounter(0),
 
- 		myLastPollTime(0)
 
- 	{
 
- 		wxMenu *menuFile = new wxMenu();
 
- 		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 + 1;
 
- 			}
 
- 			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
 
- 	};
 
- 	void OnID_ConfigDefaults(wxCommandEvent& event)
 
- 	{
 
- 		for (size_t i = 0; i < myTargets.size(); ++i)
 
- 		{
 
- 			myTargets[i]->setConfig(ConfigUtil::Default(i));
 
- 		}
 
- 	}
 
- 	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)
 
- 						{
 
- 							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 (!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;
 
- 		mmLogStatus("Load Complete");
 
- 		while (progress->Update(100, "Load Complete"))
 
- 		{
 
- 			// Wait for the user to click "Close"
 
- 			wxMilliSleep(50);
 
- 		}
 
- 		goto out;
 
- 	err:
 
- 		mmLogStatus("Load failed");
 
- 		while (progress->Update(100, "Load failed"))
 
- 		{
 
- 			// Wait for the user to click "Close"
 
- 			wxMilliSleep(50);
 
- 		}
 
- 		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 (!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();
 
- 		mmLogStatus("Save Complete");
 
- 		while (progress->Update(100, "Save Complete"))
 
- 		{
 
- 			// Wait for the user to click "Close"
 
- 			wxMilliSleep(50);
 
- 		}
 
- 		goto out;
 
- 	err:
 
- 		mmLogStatus("Save failed");
 
- 		while (progress->Update(100, "Save failed"))
 
- 		{
 
- 			// Wait for the user to click "Close"
 
- 			wxMilliSleep(50);
 
- 		}
 
- 		goto out;
 
- 	abort:
 
- 		mmLogStatus("Save Aborted");
 
- 	out:
 
- 		return;
 
- 	}
 
- 	// Note: Don't confuse this with the wxApp::OnExit virtual method
 
- 	void OnExitEvt(wxCommandEvent& event)
 
- 	{
 
- 		Close(true);
 
- 	}
 
- 	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(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)
 
- 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);
 
 
  |