TargetPanel.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  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/wrapsizer.h>
  23. #include "ConfigUtil.hh"
  24. #include "TargetPanel.hh"
  25. #include <limits>
  26. #include <sstream>
  27. #include <math.h>
  28. #include <string.h>
  29. using namespace SCSI2SD;
  30. wxDEFINE_EVENT(SCSI2SD::ConfigChangedEvent, wxCommandEvent);
  31. namespace
  32. {
  33. template<typename IntType, class WXCTRL> std::pair<IntType, bool>
  34. CtrlGetValue(WXCTRL* ctrl)
  35. {
  36. IntType value;
  37. std::stringstream conv;
  38. conv << ctrl->GetValue();
  39. conv >> value;
  40. return std::make_pair(value, static_cast<bool>(conv));
  41. }
  42. void CtrlGetFixedString(wxTextEntry* ctrl, char* dest, size_t len)
  43. {
  44. memset(dest, ' ', len);
  45. strncpy(dest, ctrl->GetValue().ToAscii(), len);
  46. }
  47. bool CtrlIsAscii(wxTextEntry* ctrl)
  48. {
  49. return ctrl->GetValue().IsAscii();
  50. }
  51. }
  52. TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
  53. wxPanel(parent),
  54. myParent(parent),
  55. myAutoStartSector(0),
  56. myStartSDSectorValidator(new wxIntegerValidator<uint32_t>),
  57. mySectorSizeValidator(new wxIntegerValidator<uint16_t>),
  58. myNumSectorValidator(new wxIntegerValidator<uint32_t>),
  59. mySizeValidator(new wxFloatingPointValidator<float>(2))
  60. {
  61. wxFlexGridSizer *fgs = new wxFlexGridSizer(13, 3, 9, 25);
  62. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  63. myEnableCtrl =
  64. new wxCheckBox(
  65. this,
  66. ID_enableCtrl,
  67. wxT("Enable SCSI Target"));
  68. fgs->Add(myEnableCtrl);
  69. // Set a non-visible string to leave room in the column for future messages
  70. fgs->Add(new wxStaticText(this, wxID_ANY, wxT(" ")));
  71. Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_enableCtrl);
  72. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SCSI ID")));
  73. myScsiIdCtrl =
  74. new wxSpinCtrl
  75. (this,
  76. ID_scsiIdCtrl,
  77. wxEmptyString,
  78. wxDefaultPosition,
  79. wxDefaultSize,
  80. wxSP_WRAP | wxSP_ARROW_KEYS,
  81. 0,
  82. 7,
  83. 0);
  84. fgs->Add(myScsiIdCtrl);
  85. myScsiIdMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  86. fgs->Add(myScsiIdMsg);
  87. Bind(wxEVT_SPINCTRL, &TargetPanel::onInput<wxSpinEvent>, this, ID_scsiIdCtrl);
  88. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Device Type")));
  89. wxString deviceTypes[] =
  90. {
  91. wxT("Hard Drive"),
  92. wxT("Removable"),
  93. wxT("CDROM"),
  94. wxT("3.5\" Floppy")
  95. };
  96. myDeviceTypeCtrl =
  97. new wxChoice(
  98. this,
  99. ID_deviceTypeCtrl,
  100. wxDefaultPosition,
  101. wxDefaultSize,
  102. sizeof(deviceTypes) / sizeof(wxString),
  103. deviceTypes
  104. );
  105. myDeviceTypeCtrl->SetSelection(0);
  106. fgs->Add(myDeviceTypeCtrl);
  107. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  108. Bind(wxEVT_CHOICE, &TargetPanel::onInput<wxCommandEvent>, this, ID_deviceTypeCtrl);
  109. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  110. myParityCtrl =
  111. new wxCheckBox(
  112. this,
  113. ID_parityCtrl,
  114. wxT("Enable Parity"));
  115. fgs->Add(myParityCtrl);
  116. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  117. Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_parityCtrl);
  118. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  119. myUnitAttCtrl =
  120. new wxCheckBox(
  121. this,
  122. ID_unitAttCtrl,
  123. wxT("Enable Unit Attention"));
  124. fgs->Add(myUnitAttCtrl);
  125. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  126. Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_unitAttCtrl);
  127. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SD card start sector")));
  128. wxWrapSizer* startContainer = new wxWrapSizer();
  129. myStartSDSectorCtrl =
  130. new wxTextCtrl(
  131. this,
  132. ID_startSDSectorCtrl,
  133. "0",
  134. wxDefaultPosition,
  135. wxDefaultSize,
  136. 0,
  137. *myStartSDSectorValidator);
  138. myStartSDSectorCtrl->SetToolTip(wxT("Supports multiple SCSI targets "
  139. "on a single memory card. In units of 512-byte sectors."));
  140. startContainer->Add(myStartSDSectorCtrl);
  141. myAutoStartSectorCtrl =
  142. new wxCheckBox(
  143. this,
  144. ID_autoStartSectorCtrl,
  145. wxT("Auto"));
  146. startContainer->Add(myAutoStartSectorCtrl);
  147. Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_autoStartSectorCtrl);
  148. fgs->Add(startContainer);
  149. myStartSDSectorMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  150. fgs->Add(myStartSDSectorMsg);
  151. Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_startSDSectorCtrl);
  152. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Sector size (bytes)")));
  153. mySectorSizeCtrl =
  154. new wxTextCtrl(
  155. this,
  156. ID_sectorSizeCtrl,
  157. "512",
  158. wxDefaultPosition,
  159. wxDefaultSize,
  160. 0,
  161. *mySectorSizeValidator);
  162. mySectorSizeCtrl->SetToolTip(wxT("Between 64 and 8192. Default of 512 is suitable in most cases."));
  163. fgs->Add(mySectorSizeCtrl);
  164. mySectorSizeMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  165. fgs->Add(mySectorSizeMsg);
  166. Bind(wxEVT_TEXT, &TargetPanel::onSizeInput, this, ID_sectorSizeCtrl);
  167. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Sector count")));
  168. myNumSectorCtrl =
  169. new wxTextCtrl(
  170. this,
  171. ID_numSectorCtrl,
  172. "",
  173. wxDefaultPosition,
  174. wxDefaultSize,
  175. 0,
  176. *myNumSectorValidator);
  177. myNumSectorCtrl->SetToolTip(wxT("Number of sectors (device size)"));
  178. fgs->Add(myNumSectorCtrl);
  179. myNumSectorMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  180. fgs->Add(myNumSectorMsg);
  181. Bind(wxEVT_TEXT, &TargetPanel::onSizeInput, this, ID_numSectorCtrl);
  182. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Device size")));
  183. wxWrapSizer* sizeContainer = new wxWrapSizer();
  184. mySizeCtrl =
  185. new wxTextCtrl(
  186. this,
  187. ID_sizeCtrl,
  188. "",
  189. wxDefaultPosition,
  190. wxDefaultSize,
  191. 0,
  192. *mySizeValidator);
  193. mySizeCtrl->SetToolTip(wxT("Device size"));
  194. sizeContainer->Add(mySizeCtrl);
  195. wxString units[] = {wxT("KB"), wxT("MB"), wxT("GB")};
  196. mySizeUnitCtrl =
  197. new wxChoice(
  198. this,
  199. ID_sizeUnitCtrl,
  200. wxDefaultPosition,
  201. wxDefaultSize,
  202. sizeof(units) / sizeof(wxString),
  203. units
  204. );
  205. sizeContainer->Add(mySizeUnitCtrl);
  206. fgs->Add(sizeContainer);
  207. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
  208. Bind(wxEVT_TEXT, &TargetPanel::onSizeInput, this, ID_sizeCtrl);
  209. Bind(wxEVT_CHOICE, &TargetPanel::onSizeInput, this, ID_sizeUnitCtrl);
  210. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Vendor")));
  211. myVendorCtrl =
  212. new wxTextCtrl(
  213. this,
  214. ID_vendorCtrl,
  215. wxEmptyString,
  216. wxDefaultPosition,
  217. wxSize(GetCharWidth() * 10, -1));
  218. myVendorCtrl->SetMaxLength(8);
  219. myVendorCtrl->SetToolTip(wxT("SCSI Vendor string. eg. ' codesrc'"));
  220. fgs->Add(myVendorCtrl);
  221. myVendorMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  222. fgs->Add(myVendorMsg);
  223. Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_vendorCtrl);
  224. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Product ID")));
  225. myProductCtrl =
  226. new wxTextCtrl(
  227. this,
  228. ID_productCtrl,
  229. wxEmptyString,
  230. wxDefaultPosition,
  231. wxSize(GetCharWidth() * 17, -1));
  232. myProductCtrl->SetMaxLength(18);
  233. myProductCtrl->SetToolTip(wxT("SCSI Product ID string. eg. 'SCSI2SD'"));
  234. fgs->Add(myProductCtrl);
  235. myProductMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  236. fgs->Add(myProductMsg);
  237. Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_productCtrl);
  238. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Revision")));
  239. myRevisionCtrl =
  240. new wxTextCtrl(
  241. this,
  242. ID_revisionCtrl,
  243. wxEmptyString,
  244. wxDefaultPosition,
  245. wxSize(GetCharWidth() * 6, -1));
  246. myRevisionCtrl->SetMaxLength(4);
  247. myRevisionCtrl->SetToolTip(wxT("SCSI device revision string. eg. '3.5a'"));
  248. fgs->Add(myRevisionCtrl);
  249. myRevisionMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  250. fgs->Add(myRevisionMsg);
  251. Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_revisionCtrl);
  252. fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Serial number")));
  253. mySerialCtrl =
  254. new wxTextCtrl(
  255. this,
  256. ID_serialCtrl,
  257. wxEmptyString,
  258. wxDefaultPosition,
  259. wxSize(GetCharWidth() * 18, -1));
  260. mySerialCtrl->SetMaxLength(16);
  261. mySerialCtrl->SetToolTip(wxT("SCSI serial number. eg. '13eab5632a'"));
  262. fgs->Add(mySerialCtrl);
  263. mySerialMsg = new wxStaticText(this, wxID_ANY, wxT(""));
  264. fgs->Add(mySerialMsg);
  265. Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_serialCtrl);
  266. wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
  267. hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);
  268. this->SetSizer(hbox);
  269. Centre();
  270. setConfig(initialConfig);
  271. evaluate();
  272. }
  273. bool
  274. TargetPanel::evaluate()
  275. {
  276. bool valid = true;
  277. std::stringstream conv;
  278. bool enabled = myEnableCtrl->IsChecked();
  279. {
  280. myScsiIdCtrl->Enable(enabled);
  281. myDeviceTypeCtrl->Enable(enabled);
  282. myParityCtrl->Enable(enabled);
  283. myUnitAttCtrl->Enable(enabled);
  284. myStartSDSectorCtrl->Enable(enabled && !myAutoStartSectorCtrl->IsChecked());
  285. myAutoStartSectorCtrl->Enable(enabled);
  286. mySectorSizeCtrl->Enable(enabled);
  287. myNumSectorCtrl->Enable(enabled);
  288. mySizeCtrl->Enable(enabled);
  289. mySizeUnitCtrl->Enable(enabled);
  290. myVendorCtrl->Enable(enabled);
  291. myProductCtrl->Enable(enabled);
  292. myRevisionCtrl->Enable(enabled);
  293. mySerialCtrl->Enable(enabled);
  294. }
  295. switch (myDeviceTypeCtrl->GetSelection())
  296. {
  297. case CONFIG_OPTICAL:
  298. mySectorSizeCtrl->ChangeValue("2048");
  299. mySectorSizeCtrl->Enable(false);
  300. break;
  301. case CONFIG_FLOPPY_14MB:
  302. mySectorSizeCtrl->ChangeValue("512");
  303. mySectorSizeCtrl->Enable(false);
  304. myNumSectorCtrl->ChangeValue("2880");
  305. myNumSectorCtrl->Enable(false);
  306. mySizeUnitCtrl->Enable(false);
  307. mySizeCtrl->Enable(false);
  308. break;
  309. };
  310. evaluateSize();
  311. if (myAutoStartSectorCtrl->IsChecked())
  312. {
  313. std::stringstream ss; ss << myAutoStartSector;
  314. myStartSDSectorCtrl->ChangeValue(ss.str());
  315. }
  316. uint32_t startSDsector;
  317. {
  318. conv << myStartSDSectorCtrl->GetValue();
  319. conv >> startSDsector;
  320. }
  321. if (!conv)
  322. // TODO check if it is beyond the current SD card.
  323. {
  324. myStartSDSectorMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Number &gt;= 0</span>"));
  325. valid = false;
  326. }
  327. else
  328. {
  329. myStartSDSectorMsg->SetLabelMarkup("");
  330. }
  331. conv.str(std::string()); conv.clear();
  332. uint16_t sectorSize(CtrlGetValue<uint16_t>(mySectorSizeCtrl).first);
  333. if (sectorSize < 64 || sectorSize > 8192)
  334. {
  335. mySectorSizeMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Must be between 64 and 8192</span>"));
  336. valid = false;
  337. }
  338. else
  339. {
  340. mySectorSizeMsg->SetLabelMarkup("");
  341. }
  342. conv.str(std::string()); conv.clear();
  343. std::pair<uint32_t, bool> numSectors(CtrlGetValue<uint32_t>(myNumSectorCtrl));
  344. if (!numSectors.second ||
  345. numSectors.first == 0 ||
  346. !convertUnitsToSectors().second)
  347. {
  348. myNumSectorMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Invalid size</span>"));
  349. valid = false;
  350. }
  351. else
  352. {
  353. myNumSectorMsg->SetLabelMarkup("");
  354. }
  355. if (!CtrlIsAscii(myVendorCtrl))
  356. {
  357. myVendorMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Invalid characters</span>"));
  358. valid = false;
  359. }
  360. else
  361. {
  362. myVendorMsg->SetLabelMarkup("");
  363. }
  364. if (!CtrlIsAscii(myProductCtrl))
  365. {
  366. myProductMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Invalid characters</span>"));
  367. valid = false;
  368. }
  369. else
  370. {
  371. myProductMsg->SetLabelMarkup("");
  372. }
  373. if (!CtrlIsAscii(myRevisionCtrl))
  374. {
  375. myRevisionMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Invalid characters</span>"));
  376. valid = false;
  377. }
  378. else
  379. {
  380. myRevisionMsg->SetLabelMarkup("");
  381. }
  382. if (!CtrlIsAscii(mySerialCtrl))
  383. {
  384. mySerialMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Invalid characters</span>"));
  385. valid = false;
  386. }
  387. else
  388. {
  389. mySerialMsg->SetLabelMarkup("");
  390. }
  391. return valid || !enabled;
  392. }
  393. template<typename EvtType> void
  394. TargetPanel::onInput(EvtType& event)
  395. {
  396. wxCommandEvent changeEvent(ConfigChangedEvent);
  397. wxPostEvent(myParent, changeEvent);
  398. }
  399. void
  400. TargetPanel::onSizeInput(wxCommandEvent& event)
  401. {
  402. if (event.GetId() != ID_numSectorCtrl)
  403. {
  404. std::stringstream ss;
  405. ss << convertUnitsToSectors().first;
  406. myNumSectorCtrl->ChangeValue(ss.str());
  407. }
  408. evaluateSize();
  409. onInput(event); // propagate
  410. }
  411. void
  412. TargetPanel::evaluateSize()
  413. {
  414. uint32_t numSectors;
  415. std::stringstream conv;
  416. conv << myNumSectorCtrl->GetValue();
  417. conv >> numSectors;
  418. conv.str(""); conv.clear();
  419. if (conv)
  420. {
  421. uint64_t bytes =
  422. uint64_t(numSectors) *
  423. CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
  424. if (bytes >= 1024 * 1024 * 1024)
  425. {
  426. conv << (bytes / (1024.0 * 1024 * 1024));
  427. mySizeUnitCtrl->SetSelection(UNIT_GB);
  428. }
  429. else if (bytes >= 1024 * 1024)
  430. {
  431. conv << (bytes / (1024.0 * 1024));
  432. mySizeUnitCtrl->SetSelection(UNIT_MB);
  433. }
  434. else
  435. {
  436. conv << (bytes / 1024.0);
  437. mySizeUnitCtrl->SetSelection(UNIT_KB);
  438. }
  439. mySizeCtrl->ChangeValue(conv.str());
  440. }
  441. }
  442. std::pair<uint32_t, bool>
  443. TargetPanel::convertUnitsToSectors() const
  444. {
  445. bool valid = true;
  446. uint64_t multiplier(0);
  447. switch (mySizeUnitCtrl->GetSelection())
  448. {
  449. case UNIT_KB: multiplier = 1024; break;
  450. case UNIT_MB: multiplier = 1024 * 1024; break;
  451. case UNIT_GB: multiplier = 1024 * 1024 * 1024; break;
  452. default: valid = false;
  453. }
  454. double size;
  455. std::stringstream conv;
  456. conv << mySizeCtrl->GetValue();
  457. conv >> size;
  458. valid = valid && conv;
  459. uint16_t sectorSize = CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
  460. uint64_t sectors = ceil(multiplier * size / sectorSize);
  461. if (sectors > std::numeric_limits<uint32_t>::max())
  462. {
  463. sectors = std::numeric_limits<uint32_t>::max();
  464. valid = false;
  465. }
  466. return std::make_pair(static_cast<uint32_t>(sectors), valid);
  467. }
  468. TargetConfig
  469. TargetPanel::getConfig() const
  470. {
  471. TargetConfig config;
  472. // Try and keep unknown/unused fields as-is to support newer firmware
  473. // versions.
  474. memcpy(&config, &myConfig, sizeof(config));
  475. bool valid = true;
  476. auto scsiId = CtrlGetValue<uint8_t>(myScsiIdCtrl);
  477. config.scsiId = scsiId.first & CONFIG_TARGET_ID_BITS;
  478. valid = valid && scsiId.second;
  479. if (myEnableCtrl->IsChecked())
  480. {
  481. config.scsiId = config.scsiId | CONFIG_TARGET_ENABLED;
  482. }
  483. config.deviceType = myDeviceTypeCtrl->GetSelection();
  484. config.flags =
  485. (myParityCtrl->IsChecked() ? CONFIG_ENABLE_PARITY : 0) |
  486. (myUnitAttCtrl->IsChecked() ? CONFIG_ENABLE_UNIT_ATTENTION : 0);
  487. auto startSDSector = CtrlGetValue<uint32_t>(myStartSDSectorCtrl);
  488. config.sdSectorStart = startSDSector.first;
  489. valid = valid && startSDSector.second;
  490. auto numSectors = CtrlGetValue<uint32_t>(myNumSectorCtrl);
  491. config.scsiSectors = numSectors.first;
  492. valid = valid && numSectors.second;
  493. auto sectorSize = CtrlGetValue<uint16_t>(mySectorSizeCtrl);
  494. config.bytesPerSector = sectorSize.first;
  495. valid = valid && sectorSize.second;
  496. CtrlGetFixedString(myVendorCtrl, config.vendor, sizeof(config.vendor));
  497. CtrlGetFixedString(myProductCtrl, config.prodId, sizeof(config.prodId));
  498. CtrlGetFixedString(myRevisionCtrl, config.revision, sizeof(config.revision));
  499. CtrlGetFixedString(mySerialCtrl, config.serial, sizeof(config.serial));
  500. return config;
  501. }
  502. void
  503. TargetPanel::setConfig(const TargetConfig& config)
  504. {
  505. memcpy(&myConfig, &config, sizeof(config));
  506. myScsiIdCtrl->SetValue(config.scsiId & CONFIG_TARGET_ID_BITS);
  507. myEnableCtrl->SetValue(config.scsiId & CONFIG_TARGET_ENABLED);
  508. myDeviceTypeCtrl->SetSelection(config.deviceType);
  509. myParityCtrl->SetValue(config.flags & CONFIG_ENABLE_PARITY);
  510. myUnitAttCtrl->SetValue(config.flags & CONFIG_ENABLE_UNIT_ATTENTION);
  511. {
  512. std::stringstream ss; ss << config.sdSectorStart;
  513. myStartSDSectorCtrl->ChangeValue(ss.str());
  514. myAutoStartSectorCtrl->SetValue(0);
  515. }
  516. {
  517. std::stringstream ss; ss << config.scsiSectors;
  518. myNumSectorCtrl->ChangeValue(ss.str());
  519. }
  520. {
  521. std::stringstream ss; ss << config.bytesPerSector;
  522. mySectorSizeCtrl->ChangeValue(ss.str());
  523. }
  524. myVendorCtrl->ChangeValue(std::string(config.vendor, sizeof(config.vendor)));
  525. myProductCtrl->ChangeValue(std::string(config.prodId, sizeof(config.prodId)));
  526. myRevisionCtrl->ChangeValue(std::string(config.revision, sizeof(config.revision)));
  527. mySerialCtrl->ChangeValue(std::string(config.serial, sizeof(config.serial)));
  528. // Set the size fields based on sector size, and evaluate inputs.
  529. wxCommandEvent fakeEvent(wxEVT_NULL, ID_numSectorCtrl);
  530. onSizeInput(fakeEvent);
  531. }
  532. bool
  533. TargetPanel::isEnabled() const
  534. {
  535. return myEnableCtrl->IsChecked();
  536. }
  537. uint8_t
  538. TargetPanel::getSCSIId() const
  539. {
  540. return CtrlGetValue<uint8_t>(myScsiIdCtrl).first & CONFIG_TARGET_ID_BITS;
  541. }
  542. std::pair<uint32_t, uint64_t>
  543. TargetPanel::getSDSectorRange() const
  544. {
  545. std::pair<uint32_t, uint64_t> result;
  546. result.first = CtrlGetValue<uint32_t>(myStartSDSectorCtrl).first;
  547. uint32_t numSCSISectors = CtrlGetValue<uint32_t>(myNumSectorCtrl).first;
  548. uint16_t scsiSectorSize = CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
  549. const int sdSector = 512; // Always 512 for SDHC/SDXC
  550. result.second = result.first +
  551. (
  552. ((uint64_t(numSCSISectors) * scsiSectorSize) + (sdSector - 1))
  553. / sdSector
  554. );
  555. return result;
  556. }
  557. void
  558. TargetPanel::setDuplicateID(bool duplicate)
  559. {
  560. if (duplicate)
  561. {
  562. myScsiIdMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Duplicate ID</span>"));
  563. }
  564. else
  565. {
  566. myScsiIdMsg->SetLabelMarkup("");
  567. }
  568. }
  569. void
  570. TargetPanel::setSDSectorOverlap(bool overlap)
  571. {
  572. if (overlap)
  573. {
  574. myStartSDSectorMsg->SetLabelMarkup(wxT("<span foreground='red' weight='bold'>Overlapping data</span>"));
  575. }
  576. else
  577. {
  578. myStartSDSectorMsg->SetLabelMarkup("");
  579. }
  580. }
  581. void
  582. TargetPanel::setAutoStartSector(uint32_t start)
  583. {
  584. myAutoStartSector = start;
  585. }