scsi2sd-util.cc 20 KB

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