scsi2sd-util.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
  2. //
  3. // This file is part of SCSI2SD.
  4. //
  5. // SCSI2SD is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // SCSI2SD is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
  17. // For compilers that support precompilation, includes "wx/wx.h".
  18. #include <wx/wxprec.h>
  19. #ifndef WX_PRECOMP
  20. #include <wx/wx.h>
  21. #endif
  22. #include <wx/app.h>
  23. #include <wx/filedlg.h>
  24. #include <wx/filefn.h>
  25. #include <wx/filename.h>
  26. #include <wx/log.h>
  27. #include <wx/notebook.h>
  28. #include <wx/progdlg.h>
  29. #include <wx/utils.h>
  30. #include <wx/wfstream.h>
  31. #include <wx/windowptr.h>
  32. #include <wx/thread.h>
  33. #include <wx/txtstrm.h>
  34. #include <zipper.hh>
  35. #include "ConfigUtil.hh"
  36. #include "TargetPanel.hh"
  37. #include "SCSI2SD_Bootloader.hh"
  38. #include "SCSI2SD_HID.hh"
  39. #include "Firmware.hh"
  40. #include <algorithm>
  41. #include <iomanip>
  42. #include <vector>
  43. #include <set>
  44. #include <sstream>
  45. #if __cplusplus >= 201103L
  46. #include <cstdint>
  47. #include <memory>
  48. using std::shared_ptr;
  49. #else
  50. #include <stdint.h>
  51. #include <tr1/memory>
  52. using std::tr1::shared_ptr;
  53. #endif
  54. #define MIN_FIRMWARE_VERSION 0x0400
  55. using namespace SCSI2SD;
  56. class ProgressWrapper
  57. {
  58. public:
  59. void setProgressDialog(
  60. const wxWindowPtr<wxGenericProgressDialog>& dlg,
  61. size_t maxRows)
  62. {
  63. myProgressDialog = dlg;
  64. myMaxRows = maxRows;
  65. myNumRows = 0;
  66. }
  67. void clearProgressDialog()
  68. {
  69. myProgressDialog->Show(false);
  70. myProgressDialog.reset();
  71. }
  72. void update(unsigned char arrayId, unsigned short rowNum)
  73. {
  74. if (!myProgressDialog) return;
  75. myNumRows++;
  76. std::stringstream ss;
  77. ss << "Writing flash array " <<
  78. static_cast<int>(arrayId) << " row " <<
  79. static_cast<int>(rowNum);
  80. wxLogMessage("%s", ss.str());
  81. myProgressDialog->Update(myNumRows, ss.str());
  82. }
  83. private:
  84. wxWindowPtr<wxGenericProgressDialog> myProgressDialog;
  85. size_t myMaxRows;
  86. size_t myNumRows;
  87. };
  88. static ProgressWrapper TheProgressWrapper;
  89. extern "C"
  90. void ProgressUpdate(unsigned char arrayId, unsigned short rowNum)
  91. {
  92. TheProgressWrapper.update(arrayId, rowNum);
  93. }
  94. namespace
  95. {
  96. static uint8_t sdCrc7(uint8_t* chr, uint8_t cnt, uint8_t crc)
  97. {
  98. uint8_t a;
  99. for(a = 0; a < cnt; a++)
  100. {
  101. uint8_t data = chr[a];
  102. uint8_t i;
  103. for(i = 0; i < 8; i++)
  104. {
  105. crc <<= 1;
  106. if ((data & 0x80) ^ (crc & 0x80))
  107. {
  108. crc ^= 0x09;
  109. }
  110. data <<= 1;
  111. }
  112. }
  113. return crc & 0x7F;
  114. }
  115. class TimerLock
  116. {
  117. public:
  118. TimerLock(wxTimer* timer) :
  119. myTimer(timer),
  120. myInterval(myTimer->GetInterval())
  121. {
  122. myTimer->Stop();
  123. };
  124. virtual ~TimerLock()
  125. {
  126. if (myTimer && myInterval > 0)
  127. {
  128. myTimer->Start(myInterval);
  129. }
  130. }
  131. private:
  132. wxTimer* myTimer;
  133. int myInterval;
  134. };
  135. class AppFrame : public wxFrame
  136. {
  137. public:
  138. AppFrame() :
  139. wxFrame(NULL, wxID_ANY, "scsi2sd-util", wxPoint(50, 50), wxSize(600, 700)),
  140. myInitialConfig(false),
  141. myTickCounter(0),
  142. myLastPollTime(0)
  143. {
  144. wxMenu *menuFile = new wxMenu();
  145. menuFile->Append(
  146. ID_SaveFile,
  147. "&Save to file...",
  148. "Save settings to local file.");
  149. menuFile->Append(
  150. ID_OpenFile,
  151. "&Open file...",
  152. "Load settings from local file.");
  153. menuFile->AppendSeparator();
  154. menuFile->Append(
  155. ID_ConfigDefaults,
  156. "Load &Defaults",
  157. "Load default configuration options.");
  158. menuFile->Append(
  159. ID_Firmware,
  160. "&Upgrade Firmware...",
  161. "Upgrade or inspect device firmware version.");
  162. menuFile->AppendSeparator();
  163. menuFile->Append(wxID_EXIT);
  164. wxMenu *menuWindow= new wxMenu();
  165. menuWindow->Append(
  166. ID_LogWindow,
  167. "Show &Log",
  168. "Show debug log window");
  169. wxMenu *menuDebug = new wxMenu();
  170. mySCSILogChk = menuDebug->AppendCheckItem(
  171. ID_SCSILog,
  172. "Log SCSI data",
  173. "Log SCSI commands");
  174. mySelfTestChk = menuDebug->AppendCheckItem(
  175. ID_SelfTest,
  176. "SCSI Standalone Self-Test",
  177. "SCSI Standalone Self-Test");
  178. wxMenu *menuHelp = new wxMenu();
  179. menuHelp->Append(wxID_ABOUT);
  180. wxMenuBar *menuBar = new wxMenuBar();
  181. menuBar->Append( menuFile, "&File" );
  182. menuBar->Append( menuDebug, "&Debug" );
  183. menuBar->Append( menuWindow, "&Window" );
  184. menuBar->Append( menuHelp, "&Help" );
  185. SetMenuBar( menuBar );
  186. CreateStatusBar();
  187. {
  188. wxPanel* cfgPanel = new wxPanel(this);
  189. wxFlexGridSizer *fgs = new wxFlexGridSizer(3, 1, 15, 15);
  190. cfgPanel->SetSizer(fgs);
  191. // Empty space below menu bar.
  192. fgs->Add(5, 5, wxALL);
  193. wxNotebook* tabs = new wxNotebook(cfgPanel, ID_Notebook);
  194. for (int i = 0; i < MAX_SCSI_TARGETS; ++i)
  195. {
  196. TargetPanel* target =
  197. new TargetPanel(tabs, ConfigUtil::Default(i));
  198. myTargets.push_back(target);
  199. std::stringstream ss;
  200. ss << "Device " << (i + 1);
  201. tabs->AddPage(target, ss.str());
  202. target->Fit();
  203. }
  204. tabs->Fit();
  205. fgs->Add(tabs);
  206. wxPanel* btnPanel = new wxPanel(cfgPanel);
  207. wxFlexGridSizer *btnFgs = new wxFlexGridSizer(1, 2, 5, 5);
  208. btnPanel->SetSizer(btnFgs);
  209. myLoadButton =
  210. new wxButton(btnPanel, ID_BtnLoad, wxT("Load from device"));
  211. btnFgs->Add(myLoadButton);
  212. mySaveButton =
  213. new wxButton(btnPanel, ID_BtnSave, wxT("Save to device"));
  214. btnFgs->Add(mySaveButton);
  215. fgs->Add(btnPanel);
  216. btnPanel->Fit();
  217. cfgPanel->Fit();
  218. }
  219. //Fit(); // Needed to reduce window size on Windows
  220. FitInside(); // Needed on Linux to prevent status bar overlap
  221. myLogWindow = new wxLogWindow(this, wxT("scsi2sd-util debug log"), true);
  222. myLogWindow->PassMessages(false); // Prevent messagebox popups
  223. myTimer = new wxTimer(this, ID_Timer);
  224. myTimer->Start(16); //ms, suitable for scsi debug logging
  225. }
  226. private:
  227. wxLogWindow* myLogWindow;
  228. std::vector<TargetPanel*> myTargets;
  229. wxButton* myLoadButton;
  230. wxButton* mySaveButton;
  231. wxMenuItem* mySCSILogChk;
  232. wxMenuItem* mySelfTestChk;
  233. wxTimer* myTimer;
  234. shared_ptr<HID> myHID;
  235. shared_ptr<Bootloader> myBootloader;
  236. bool myInitialConfig;
  237. uint8_t myTickCounter;
  238. time_t myLastPollTime;
  239. void mmLogStatus(const std::string& msg)
  240. {
  241. // We set PassMessages to false on our log window to prevent popups, but
  242. // this also prevents wxLogStatus from updating the status bar.
  243. SetStatusText(msg);
  244. wxLogMessage(this, "%s", msg.c_str());
  245. }
  246. void onConfigChanged(wxCommandEvent& event)
  247. {
  248. evaluate();
  249. }
  250. void evaluate()
  251. {
  252. bool valid = true;
  253. // Check for duplicate SCSI IDs
  254. std::set<uint8_t> enabledID;
  255. // Check for overlapping SD sectors.
  256. std::vector<std::pair<uint32_t, uint64_t> > sdSectors;
  257. bool isTargetEnabled = false; // Need at least one enabled
  258. uint32_t autoStartSector = 0;
  259. for (size_t i = 0; i < myTargets.size(); ++i)
  260. {
  261. myTargets[i]->setAutoStartSector(autoStartSector);
  262. valid = myTargets[i]->evaluate() && valid;
  263. if (myTargets[i]->isEnabled())
  264. {
  265. isTargetEnabled = true;
  266. uint8_t scsiID = myTargets[i]->getSCSIId();
  267. if (enabledID.find(scsiID) != enabledID.end())
  268. {
  269. myTargets[i]->setDuplicateID(true);
  270. valid = false;
  271. }
  272. else
  273. {
  274. enabledID.insert(scsiID);
  275. myTargets[i]->setDuplicateID(false);
  276. }
  277. auto sdSectorRange = myTargets[i]->getSDSectorRange();
  278. for (auto it(sdSectors.begin()); it != sdSectors.end(); ++it)
  279. {
  280. if (sdSectorRange.first < it->second &&
  281. sdSectorRange.second > it->first)
  282. {
  283. valid = false;
  284. myTargets[i]->setSDSectorOverlap(true);
  285. }
  286. else
  287. {
  288. myTargets[i]->setSDSectorOverlap(false);
  289. }
  290. }
  291. sdSectors.push_back(sdSectorRange);
  292. autoStartSector = sdSectorRange.second;
  293. }
  294. else
  295. {
  296. myTargets[i]->setDuplicateID(false);
  297. myTargets[i]->setSDSectorOverlap(false);
  298. }
  299. }
  300. valid = valid && isTargetEnabled; // Need at least one.
  301. mySaveButton->Enable(
  302. valid &&
  303. myHID &&
  304. (myHID->getFirmwareVersion() >= MIN_FIRMWARE_VERSION));
  305. myLoadButton->Enable(
  306. myHID &&
  307. (myHID->getFirmwareVersion() >= MIN_FIRMWARE_VERSION));
  308. }
  309. enum
  310. {
  311. ID_ConfigDefaults = wxID_HIGHEST + 1,
  312. ID_Firmware,
  313. ID_Timer,
  314. ID_Notebook,
  315. ID_BtnLoad,
  316. ID_BtnSave,
  317. ID_LogWindow,
  318. ID_SCSILog,
  319. ID_SelfTest,
  320. ID_SaveFile,
  321. ID_OpenFile
  322. };
  323. void OnID_ConfigDefaults(wxCommandEvent& event)
  324. {
  325. for (size_t i = 0; i < myTargets.size(); ++i)
  326. {
  327. myTargets[i]->setConfig(ConfigUtil::Default(i));
  328. }
  329. }
  330. void OnID_SaveFile(wxCommandEvent& event)
  331. {
  332. TimerLock lock(myTimer);
  333. wxFileDialog dlg(
  334. this,
  335. "Save config settings",
  336. "",
  337. "",
  338. "XML files (*.xml)|*.xml",
  339. wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
  340. if (dlg.ShowModal() == wxID_CANCEL) return;
  341. wxFileOutputStream file(dlg.GetPath());
  342. if (!file.IsOk())
  343. {
  344. wxLogError("Cannot save settings to file '%s'.", dlg.GetPath());
  345. return;
  346. }
  347. wxTextOutputStream s(file);
  348. s << "<SCSI2SD>\n";
  349. for (size_t i = 0; i < myTargets.size(); ++i)
  350. {
  351. s << ConfigUtil::toXML(myTargets[i]->getConfig());
  352. }
  353. s << "</SCSI2SD>\n";
  354. }
  355. void OnID_OpenFile(wxCommandEvent& event)
  356. {
  357. TimerLock lock(myTimer);
  358. wxFileDialog dlg(
  359. this,
  360. "Load config settings",
  361. "",
  362. "",
  363. "XML files (*.xml)|*.xml",
  364. wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  365. if (dlg.ShowModal() == wxID_CANCEL) return;
  366. try
  367. {
  368. std::vector<TargetConfig> configs(
  369. ConfigUtil::fromXML(std::string(dlg.GetPath())));
  370. size_t i;
  371. for (i = 0; i < configs.size() && i < myTargets.size(); ++i)
  372. {
  373. myTargets[i]->setConfig(configs[i]);
  374. }
  375. for (; i < myTargets.size(); ++i)
  376. {
  377. myTargets[i]->setConfig(ConfigUtil::Default(i));
  378. }
  379. }
  380. catch (std::exception& e)
  381. {
  382. wxLogError(
  383. "Cannot load settings from file '%s'.\n%s",
  384. dlg.GetPath(),
  385. e.what());
  386. wxMessageBox(
  387. e.what(),
  388. "Load error",
  389. wxOK | wxICON_ERROR);
  390. }
  391. }
  392. void OnID_Firmware(wxCommandEvent& event)
  393. {
  394. TimerLock lock(myTimer);
  395. doFirmwareUpdate();
  396. }
  397. void OnID_LogWindow(wxCommandEvent& event)
  398. {
  399. myLogWindow->Show();
  400. }
  401. void doFirmwareUpdate()
  402. {
  403. wxFileDialog dlg(
  404. this,
  405. "Load firmware file",
  406. "",
  407. "",
  408. "SCSI2SD Firmware files (*.scsi2sd;*.cyacd)|*.cyacd;*.scsi2sd",
  409. wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  410. if (dlg.ShowModal() == wxID_CANCEL) return;
  411. std::string filename(dlg.GetPath());
  412. wxWindowPtr<wxGenericProgressDialog> progress(
  413. new wxGenericProgressDialog(
  414. "Searching for bootloader",
  415. "Searching for bootloader",
  416. 100,
  417. this,
  418. wxPD_AUTO_HIDE | wxPD_CAN_ABORT)
  419. );
  420. mmLogStatus("Searching for bootloader");
  421. while (true)
  422. {
  423. try
  424. {
  425. if (!myHID) myHID.reset(HID::Open());
  426. if (myHID)
  427. {
  428. mmLogStatus("Resetting SCSI2SD into bootloader");
  429. myHID->enterBootloader();
  430. myHID.reset();
  431. }
  432. if (!myBootloader)
  433. {
  434. myBootloader.reset(Bootloader::Open());
  435. if (myBootloader)
  436. {
  437. mmLogStatus("Bootloader found");
  438. break;
  439. }
  440. }
  441. else if (myBootloader)
  442. {
  443. // Verify the USB HID connection is valid
  444. if (!myBootloader->ping())
  445. {
  446. mmLogStatus("Bootloader ping failed");
  447. myBootloader.reset();
  448. }
  449. else
  450. {
  451. mmLogStatus("Bootloader found");
  452. break;
  453. }
  454. }
  455. }
  456. catch (std::exception& e)
  457. {
  458. mmLogStatus(e.what());
  459. myHID.reset();
  460. myBootloader.reset();
  461. }
  462. wxMilliSleep(100);
  463. if (!progress->Pulse())
  464. {
  465. return; // user cancelled.
  466. }
  467. }
  468. int totalFlashRows = 0;
  469. std::string tmpFile;
  470. try
  471. {
  472. zipper::ReaderPtr reader(new zipper::FileReader(filename));
  473. zipper::Decompressor decomp(reader);
  474. std::vector<zipper::CompressedFilePtr> files(decomp.getEntries());
  475. for (auto it(files.begin()); it != files.end(); it++)
  476. {
  477. if (myBootloader->isCorrectFirmware((*it)->getPath()))
  478. {
  479. std::stringstream msg;
  480. msg << "Found firmware entry " << (*it)->getPath() <<
  481. " within archive " << filename;
  482. mmLogStatus(msg.str());
  483. tmpFile =
  484. wxFileName::CreateTempFileName(
  485. wxT("SCSI2SD_Firmware"), static_cast<wxFile*>(NULL)
  486. );
  487. zipper::FileWriter out(tmpFile);
  488. (*it)->decompress(out);
  489. msg.clear();
  490. msg << "Firmware extracted to " << tmpFile;
  491. mmLogStatus(msg.str());
  492. break;
  493. }
  494. }
  495. if (tmpFile.empty())
  496. {
  497. // TODO allow "force" option
  498. wxMessageBox(
  499. "Wrong filename",
  500. "Wrong filename",
  501. wxOK | wxICON_ERROR);
  502. return;
  503. }
  504. Firmware firmware(tmpFile);
  505. totalFlashRows = firmware.totalFlashRows();
  506. }
  507. catch (std::exception& e)
  508. {
  509. mmLogStatus(e.what());
  510. std::stringstream msg;
  511. msg << "Could not open firmware file: " << e.what();
  512. wxMessageBox(
  513. msg.str(),
  514. "Bad file",
  515. wxOK | wxICON_ERROR);
  516. wxRemoveFile(tmpFile);
  517. return;
  518. }
  519. {
  520. wxWindowPtr<wxGenericProgressDialog> progress(
  521. new wxGenericProgressDialog(
  522. "Loading firmware",
  523. "Loading firmware",
  524. totalFlashRows,
  525. this,
  526. wxPD_AUTO_HIDE | wxPD_REMAINING_TIME)
  527. );
  528. TheProgressWrapper.setProgressDialog(progress, totalFlashRows);
  529. }
  530. std::stringstream msg;
  531. msg << "Upgrading firmware from file: " << tmpFile;
  532. mmLogStatus(msg.str());
  533. try
  534. {
  535. myBootloader->load(tmpFile, &ProgressUpdate);
  536. TheProgressWrapper.clearProgressDialog();
  537. wxMessageBox(
  538. "Firmware update successful",
  539. "Firmware OK",
  540. wxOK);
  541. mmLogStatus("Firmware update successful");
  542. myHID.reset();
  543. myBootloader.reset();
  544. }
  545. catch (std::exception& e)
  546. {
  547. TheProgressWrapper.clearProgressDialog();
  548. mmLogStatus(e.what());
  549. myHID.reset();
  550. myBootloader.reset();
  551. wxMessageBox(
  552. "Firmware Update Failed",
  553. e.what(),
  554. wxOK | wxICON_ERROR);
  555. wxRemoveFile(tmpFile);
  556. }
  557. }
  558. void dumpSCSICommand(std::vector<uint8_t> buf)
  559. {
  560. std::stringstream msg;
  561. msg << std::hex;
  562. for (size_t i = 0; i < 32 && i < buf.size(); ++i)
  563. {
  564. msg << std::setfill('0') << std::setw(2) <<
  565. static_cast<int>(buf[i]) << ' ';
  566. }
  567. wxLogMessage(this, msg.str().c_str());
  568. }
  569. void logSCSI()
  570. {
  571. if (!mySCSILogChk->IsChecked() ||
  572. !myHID)
  573. {
  574. return;
  575. }
  576. try
  577. {
  578. std::vector<uint8_t> info(HID::HID_PACKET_SIZE);
  579. if (myHID->readSCSIDebugInfo(info))
  580. {
  581. dumpSCSICommand(info);
  582. }
  583. }
  584. catch (std::exception& e)
  585. {
  586. wxLogWarning(this, e.what());
  587. myHID.reset();
  588. }
  589. }
  590. void OnID_Timer(wxTimerEvent& event)
  591. {
  592. logSCSI();
  593. time_t now = time(NULL);
  594. if (now == myLastPollTime) return;
  595. myLastPollTime = now;
  596. // Check if we are connected to the HID device.
  597. // AND/or bootloader device.
  598. try
  599. {
  600. if (myBootloader)
  601. {
  602. // Verify the USB HID connection is valid
  603. if (!myBootloader->ping())
  604. {
  605. myBootloader.reset();
  606. }
  607. }
  608. if (!myBootloader)
  609. {
  610. myBootloader.reset(Bootloader::Open());
  611. if (myBootloader)
  612. {
  613. mmLogStatus("SCSI2SD Bootloader Ready");
  614. }
  615. }
  616. int supressLog = 0;
  617. if (myHID && myHID->getFirmwareVersion() < MIN_FIRMWARE_VERSION)
  618. {
  619. // No method to check connection is still valid.
  620. // So assume it isn't.
  621. myHID.reset();
  622. supressLog = 1;
  623. }
  624. else if (myHID && !myHID->ping())
  625. {
  626. // Verify the USB HID connection is valid
  627. myHID.reset();
  628. }
  629. if (!myHID)
  630. {
  631. myHID.reset(HID::Open());
  632. if (myHID)
  633. {
  634. if (myHID->getFirmwareVersion() < MIN_FIRMWARE_VERSION)
  635. {
  636. if (!supressLog)
  637. {
  638. // Oh dear, old firmware
  639. std::stringstream msg;
  640. msg << "Firmware update required. Version " <<
  641. myHID->getFirmwareVersionStr();
  642. mmLogStatus(msg.str());
  643. }
  644. }
  645. else
  646. {
  647. std::stringstream msg;
  648. msg << "SCSI2SD Ready, firmware version " <<
  649. myHID->getFirmwareVersionStr();
  650. mmLogStatus(msg.str());
  651. std::vector<uint8_t> csd(myHID->getSD_CSD());
  652. std::vector<uint8_t> cid(myHID->getSD_CID());
  653. std::stringstream sdinfo;
  654. sdinfo << "SD Capacity (512-byte sectors): " <<
  655. myHID->getSDCapacity() << std::endl;
  656. sdinfo << "SD CSD Register: ";
  657. if (sdCrc7(&csd[0], 15, 0) != (csd[15] >> 1))
  658. {
  659. sdinfo << "BADCRC ";
  660. }
  661. for (size_t i = 0; i < csd.size(); ++i)
  662. {
  663. sdinfo <<
  664. std::hex << std::setfill('0') << std::setw(2) <<
  665. static_cast<int>(csd[i]);
  666. }
  667. sdinfo << std::endl;
  668. sdinfo << "SD CID Register: ";
  669. if (sdCrc7(&cid[0], 15, 0) != (cid[15] >> 1))
  670. {
  671. sdinfo << "BADCRC ";
  672. }
  673. for (size_t i = 0; i < cid.size(); ++i)
  674. {
  675. sdinfo <<
  676. std::hex << std::setfill('0') << std::setw(2) <<
  677. static_cast<int>(cid[i]);
  678. }
  679. wxLogMessage(this, "%s", sdinfo.str());
  680. if (mySelfTestChk->IsChecked())
  681. {
  682. std::stringstream scsiInfo;
  683. scsiInfo << "SCSI Self-Test: " <<
  684. (myHID->scsiSelfTest() ? "Passed" : "FAIL");
  685. wxLogMessage(this, "%s", scsiInfo.str());
  686. }
  687. if (!myInitialConfig)
  688. {
  689. /* This doesn't work properly, and causes crashes.
  690. wxCommandEvent loadEvent(wxEVT_NULL, ID_BtnLoad);
  691. GetEventHandler()->AddPendingEvent(loadEvent);
  692. */
  693. }
  694. }
  695. }
  696. else
  697. {
  698. char ticks[] = {'/', '-', '\\', '|'};
  699. std::stringstream ss;
  700. ss << "Searching for SCSI2SD device " << ticks[myTickCounter % sizeof(ticks)];
  701. myTickCounter++;
  702. SetStatusText(ss.str());
  703. }
  704. }
  705. }
  706. catch (std::runtime_error& e)
  707. {
  708. std::cerr << e.what() << std::endl;
  709. mmLogStatus(e.what());
  710. }
  711. evaluate();
  712. }
  713. void doLoad(wxCommandEvent& event)
  714. {
  715. TimerLock lock(myTimer);
  716. if (!myHID) return;
  717. mmLogStatus("Loading configuration");
  718. wxWindowPtr<wxGenericProgressDialog> progress(
  719. new wxGenericProgressDialog(
  720. "Load config settings",
  721. "Loading config settings",
  722. 100,
  723. this,
  724. wxPD_CAN_ABORT | wxPD_REMAINING_TIME)
  725. );
  726. int flashRow = SCSI_CONFIG_0_ROW;
  727. int currentProgress = 0;
  728. int totalProgress = myTargets.size() * SCSI_CONFIG_ROWS;
  729. for (size_t i = 0;
  730. i < myTargets.size();
  731. ++i, flashRow += SCSI_CONFIG_ROWS)
  732. {
  733. std::vector<uint8_t> raw(sizeof(TargetConfig));
  734. for (size_t j = 0; j < SCSI_CONFIG_ROWS; ++j)
  735. {
  736. std::stringstream ss;
  737. ss << "Reading flash array " << SCSI_CONFIG_ARRAY <<
  738. " row " << (flashRow + j);
  739. mmLogStatus(ss.str());
  740. currentProgress += 1;
  741. if (currentProgress == totalProgress)
  742. {
  743. ss.str("Load Complete.");
  744. mmLogStatus("Load Complete.");
  745. }
  746. if (!progress->Update(
  747. (100 * currentProgress) / totalProgress,
  748. ss.str()
  749. )
  750. )
  751. {
  752. goto abort;
  753. }
  754. std::vector<uint8_t> flashData;
  755. try
  756. {
  757. myHID->readFlashRow(
  758. SCSI_CONFIG_ARRAY, flashRow + j, flashData);
  759. }
  760. catch (std::runtime_error& e)
  761. {
  762. mmLogStatus(e.what());
  763. goto err;
  764. }
  765. std::copy(
  766. flashData.begin(),
  767. flashData.end(),
  768. &raw[j * SCSI_CONFIG_ROW_SIZE]);
  769. }
  770. myTargets[i]->setConfig(ConfigUtil::fromBytes(&raw[0]));
  771. }
  772. myInitialConfig = true;
  773. goto out;
  774. err:
  775. mmLogStatus("Load failed");
  776. progress->Update(100, "Load failed");
  777. goto out;
  778. abort:
  779. mmLogStatus("Load Aborted");
  780. out:
  781. return;
  782. }
  783. void doSave(wxCommandEvent& event)
  784. {
  785. TimerLock lock(myTimer);
  786. if (!myHID) return;
  787. mmLogStatus("Saving configuration");
  788. wxWindowPtr<wxGenericProgressDialog> progress(
  789. new wxGenericProgressDialog(
  790. "Save config settings",
  791. "Saving config settings",
  792. 100,
  793. this,
  794. wxPD_CAN_ABORT | wxPD_REMAINING_TIME)
  795. );
  796. int flashRow = SCSI_CONFIG_0_ROW;
  797. int currentProgress = 0;
  798. int totalProgress = myTargets.size() * SCSI_CONFIG_ROWS;
  799. for (size_t i = 0;
  800. i < myTargets.size();
  801. ++i, flashRow += SCSI_CONFIG_ROWS)
  802. {
  803. TargetConfig config(myTargets[i]->getConfig());
  804. std::vector<uint8_t> raw(ConfigUtil::toBytes(config));
  805. for (size_t j = 0; j < SCSI_CONFIG_ROWS; ++j)
  806. {
  807. std::stringstream ss;
  808. ss << "Programming flash array " << SCSI_CONFIG_ARRAY <<
  809. " row " << (flashRow + j);
  810. mmLogStatus(ss.str());
  811. currentProgress += 1;
  812. if (currentProgress == totalProgress)
  813. {
  814. ss.str("Save Complete.");
  815. mmLogStatus("Save Complete.");
  816. }
  817. if (!progress->Update(
  818. (100 * currentProgress) / totalProgress,
  819. ss.str()
  820. )
  821. )
  822. {
  823. goto abort;
  824. }
  825. std::vector<uint8_t> flashData(SCSI_CONFIG_ROW_SIZE, 0);
  826. std::copy(
  827. &raw[j * SCSI_CONFIG_ROW_SIZE],
  828. &raw[(1+j) * SCSI_CONFIG_ROW_SIZE],
  829. flashData.begin());
  830. try
  831. {
  832. myHID->writeFlashRow(
  833. SCSI_CONFIG_ARRAY, flashRow + j, flashData);
  834. }
  835. catch (std::runtime_error& e)
  836. {
  837. mmLogStatus(e.what());
  838. goto err;
  839. }
  840. }
  841. }
  842. // Reboot so new settings take effect.
  843. myHID->enterBootloader();
  844. myHID.reset();
  845. goto out;
  846. err:
  847. mmLogStatus("Save failed");
  848. progress->Update(100, "Save failed");
  849. goto out;
  850. abort:
  851. mmLogStatus("Save Aborted");
  852. out:
  853. return;
  854. }
  855. // Note: Don't confuse this with the wxApp::OnExit virtual method
  856. void OnExitEvt(wxCommandEvent& event);
  857. void OnCloseEvt(wxCloseEvent& event);
  858. void OnAbout(wxCommandEvent& event)
  859. {
  860. wxMessageBox(
  861. "SCSI2SD (scsi2sd-util)\n"
  862. "Copyright (C) 2014 Michael McMaster <michael@codesrc.com>\n"
  863. "\n"
  864. "This program is free software: you can redistribute it and/or modify\n"
  865. "it under the terms of the GNU General Public License as published by\n"
  866. "the Free Software Foundation, either version 3 of the License, or\n"
  867. "(at your option) any later version.\n"
  868. "\n"
  869. "This program is distributed in the hope that it will be useful,\n"
  870. "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  871. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
  872. "GNU General Public License for more details.\n"
  873. "\n"
  874. "You should have received a copy of the GNU General Public License\n"
  875. "along with this program. If not, see <http://www.gnu.org/licenses/>.\n",
  876. "About scsi2sd-util", wxOK | wxICON_INFORMATION );
  877. }
  878. wxDECLARE_EVENT_TABLE();
  879. };
  880. wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
  881. EVT_MENU(AppFrame::ID_ConfigDefaults, AppFrame::OnID_ConfigDefaults)
  882. EVT_MENU(AppFrame::ID_Firmware, AppFrame::OnID_Firmware)
  883. EVT_MENU(AppFrame::ID_LogWindow, AppFrame::OnID_LogWindow)
  884. EVT_MENU(AppFrame::ID_SaveFile, AppFrame::OnID_SaveFile)
  885. EVT_MENU(AppFrame::ID_OpenFile, AppFrame::OnID_OpenFile)
  886. EVT_MENU(wxID_EXIT, AppFrame::OnExitEvt)
  887. EVT_MENU(wxID_ABOUT, AppFrame::OnAbout)
  888. EVT_TIMER(AppFrame::ID_Timer, AppFrame::OnID_Timer)
  889. EVT_COMMAND(wxID_ANY, ConfigChangedEvent, AppFrame::onConfigChanged)
  890. EVT_BUTTON(ID_BtnSave, AppFrame::doSave)
  891. EVT_BUTTON(ID_BtnLoad, AppFrame::doLoad)
  892. EVT_CLOSE(AppFrame::OnCloseEvt)
  893. wxEND_EVENT_TABLE()
  894. class App : public wxApp
  895. {
  896. public:
  897. virtual bool OnInit()
  898. {
  899. AppFrame* frame = new AppFrame();
  900. frame->Show(true);
  901. SetTopWindow(frame);
  902. return true;
  903. }
  904. };
  905. } // namespace
  906. // Main Method
  907. wxIMPLEMENT_APP(App);
  908. void
  909. AppFrame::OnExitEvt(wxCommandEvent& event)
  910. {
  911. wxGetApp().ExitMainLoop();
  912. }
  913. void
  914. AppFrame::OnCloseEvt(wxCloseEvent& event)
  915. {
  916. wxGetApp().ExitMainLoop();
  917. }