scsi2sd-util.cc 22 KB

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