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