Merge branch 'master' of ssh://webhost.codesrc.com/home/michael/projects/SCSI2SD
[SCSI2SD.git] / software / scsi2sd-util / TargetPanel.cc
index 565b02d..eb04e55 100644 (file)
@@ -51,7 +51,9 @@ namespace
        void CtrlGetFixedString(wxTextEntry* ctrl, char* dest, size_t len)
        {
                memset(dest, ' ', len);
-               strncpy(dest, ctrl->GetValue().ToAscii(), len);
+               std::string str(ctrl->GetValue().ToAscii());
+               // Don't use strncpy - we need to avoid NULL's
+               memcpy(dest, str.c_str(), std::min(len, str.size()));
        }
 
        bool CtrlIsAscii(wxTextEntry* ctrl)
@@ -64,12 +66,13 @@ namespace
 TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        wxPanel(parent),
        myParent(parent),
+       myAutoStartSector(0),
        myStartSDSectorValidator(new wxIntegerValidator<uint32_t>),
        mySectorSizeValidator(new wxIntegerValidator<uint16_t>),
        myNumSectorValidator(new wxIntegerValidator<uint32_t>),
        mySizeValidator(new wxFloatingPointValidator<float>(2))
 {
-       wxFlexGridSizer *fgs = new wxFlexGridSizer(12, 3, 9, 25);
+       wxFlexGridSizer *fgs = new wxFlexGridSizer(13, 3, 9, 25);
 
        fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
        myEnableCtrl =
@@ -100,28 +103,69 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        fgs->Add(myScsiIdMsg);
        Bind(wxEVT_SPINCTRL, &TargetPanel::onInput<wxSpinEvent>, this, ID_scsiIdCtrl);
 
+       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Device Type")));
+       wxString deviceTypes[] =
+       {
+               wxT("Hard Drive"),
+               wxT("Removable"),
+               wxT("CDROM"),
+               wxT("3.5\" Floppy"),
+               wxT("Magneto optical")
+       };
+       myDeviceTypeCtrl =
+               new wxChoice(
+                       this,
+                       ID_deviceTypeCtrl,
+                       wxDefaultPosition,
+                       wxDefaultSize,
+                       sizeof(deviceTypes) / sizeof(wxString),
+                       deviceTypes
+                       );
+       myDeviceTypeCtrl->SetSelection(0);
+       fgs->Add(myDeviceTypeCtrl);
+       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
+       Bind(wxEVT_CHOICE, &TargetPanel::onInput<wxCommandEvent>, this, ID_deviceTypeCtrl);
+
        fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
        myParityCtrl =
                new wxCheckBox(
                        this,
                        ID_parityCtrl,
                        wxT("Enable Parity"));
+       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."));
        fgs->Add(myParityCtrl);
-       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
        Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_parityCtrl);
 
-       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
        myUnitAttCtrl =
                new wxCheckBox(
                        this,
                        ID_unitAttCtrl,
                        wxT("Enable Unit Attention"));
-
+       myUnitAttCtrl->SetToolTip(wxT("Enable this to inform the host of changes after hot-swapping SD cards. Causes problems with Mac Plus."));
        fgs->Add(myUnitAttCtrl);
-       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
        Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_unitAttCtrl);
 
+       fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
+       myScsi2Ctrl =
+               new wxCheckBox(
+                       this,
+                       ID_scsi2Ctrl,
+                       wxT("Enable SCSI2 Mode"));
+       myScsi2Ctrl->SetToolTip(wxT("Enable high-performance mode. May cause problems with SASI/SCSI1 hosts."));
+       fgs->Add(myScsi2Ctrl);
+       Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_scsi2Ctrl);
+
+       myGlitchCtrl =
+               new wxCheckBox(
+                       this,
+                       ID_glitchCtrl,
+                       wxT("Disable glitch filter"));
+       myGlitchCtrl->SetToolTip(wxT("Improve performance at the cost of noise immunity. Only use with short cables."));
+       fgs->Add(myGlitchCtrl);
+       Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_glitchCtrl);
+
        fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SD card start sector")));
+       wxWrapSizer* startContainer = new wxWrapSizer();
        myStartSDSectorCtrl =
                new wxTextCtrl(
                        this,
@@ -133,11 +177,20 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
                        *myStartSDSectorValidator);
        myStartSDSectorCtrl->SetToolTip(wxT("Supports multiple SCSI targets "
                "on a single memory card. In units of 512-byte sectors."));
-       fgs->Add(myStartSDSectorCtrl);
+       startContainer->Add(myStartSDSectorCtrl);
+       myAutoStartSectorCtrl =
+               new wxCheckBox(
+                       this,
+                       ID_autoStartSectorCtrl,
+                       wxT("Auto"));
+       startContainer->Add(myAutoStartSectorCtrl);
+       Bind(wxEVT_CHECKBOX, &TargetPanel::onInput<wxCommandEvent>, this, ID_autoStartSectorCtrl);
+       fgs->Add(startContainer);
        myStartSDSectorMsg = new wxStaticText(this, wxID_ANY, wxT(""));
        fgs->Add(myStartSDSectorMsg);
        Bind(wxEVT_TEXT, &TargetPanel::onInput<wxCommandEvent>, this, ID_startSDSectorCtrl);
 
+
        fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Sector size (bytes)")));
        mySectorSizeCtrl =
                new wxTextCtrl(
@@ -186,7 +239,7 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        mySizeCtrl->SetToolTip(wxT("Device size"));
        sizeContainer->Add(mySizeCtrl);
        wxString units[] = {wxT("KB"), wxT("MB"), wxT("GB")};
-       mySizeUnitCtrl = 
+       mySizeUnitCtrl =
                new wxChoice(
                        this,
                        ID_sizeUnitCtrl,
@@ -205,7 +258,10 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        myVendorCtrl =
                new wxTextCtrl(
                        this,
-                       ID_vendorCtrl);
+                       ID_vendorCtrl,
+                       wxEmptyString,
+                       wxDefaultPosition,
+                       wxSize(GetCharWidth() * 10, -1));
        myVendorCtrl->SetMaxLength(8);
        myVendorCtrl->SetToolTip(wxT("SCSI Vendor string. eg. ' codesrc'"));
        fgs->Add(myVendorCtrl);
@@ -217,8 +273,11 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        myProductCtrl =
                new wxTextCtrl(
                        this,
-                       ID_productCtrl);
-       myProductCtrl->SetMaxLength(16);
+                       ID_productCtrl,
+                       wxEmptyString,
+                       wxDefaultPosition,
+                       wxSize(GetCharWidth() * 17, -1));
+       myProductCtrl->SetMaxLength(18);
        myProductCtrl->SetToolTip(wxT("SCSI Product ID string. eg. 'SCSI2SD'"));
        fgs->Add(myProductCtrl);
        myProductMsg = new wxStaticText(this, wxID_ANY, wxT(""));
@@ -229,7 +288,10 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        myRevisionCtrl =
                new wxTextCtrl(
                        this,
-                       ID_revisionCtrl);
+                       ID_revisionCtrl,
+                       wxEmptyString,
+                       wxDefaultPosition,
+                       wxSize(GetCharWidth() * 6, -1));
        myRevisionCtrl->SetMaxLength(4);
        myRevisionCtrl->SetToolTip(wxT("SCSI device revision string. eg. '3.5a'"));
        fgs->Add(myRevisionCtrl);
@@ -241,7 +303,10 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
        mySerialCtrl =
                new wxTextCtrl(
                        this,
-                       ID_serialCtrl);
+                       ID_serialCtrl,
+                       wxEmptyString,
+                       wxDefaultPosition,
+                       wxSize(GetCharWidth() * 18, -1));
        mySerialCtrl->SetMaxLength(16);
        mySerialCtrl->SetToolTip(wxT("SCSI serial number. eg. '13eab5632a'"));
        fgs->Add(mySerialCtrl);
@@ -265,6 +330,49 @@ TargetPanel::evaluate()
        bool valid = true;
        std::stringstream conv;
 
+       bool enabled = myEnableCtrl->IsChecked();
+       {
+               myScsiIdCtrl->Enable(enabled);
+               myDeviceTypeCtrl->Enable(enabled);
+               myParityCtrl->Enable(enabled);
+               myUnitAttCtrl->Enable(enabled);
+               myScsi2Ctrl->Enable(enabled);
+               myGlitchCtrl->Enable(enabled);
+               myStartSDSectorCtrl->Enable(enabled && !myAutoStartSectorCtrl->IsChecked());
+               myAutoStartSectorCtrl->Enable(enabled);
+               mySectorSizeCtrl->Enable(enabled);
+               myNumSectorCtrl->Enable(enabled);
+               mySizeCtrl->Enable(enabled);
+               mySizeUnitCtrl->Enable(enabled);
+               myVendorCtrl->Enable(enabled);
+               myProductCtrl->Enable(enabled);
+               myRevisionCtrl->Enable(enabled);
+               mySerialCtrl->Enable(enabled);
+       }
+
+       switch (myDeviceTypeCtrl->GetSelection())
+       {
+       case CONFIG_OPTICAL:
+               mySectorSizeCtrl->ChangeValue("2048");
+               mySectorSizeCtrl->Enable(false);
+               break;
+       case CONFIG_FLOPPY_14MB:
+               mySectorSizeCtrl->ChangeValue("512");
+               mySectorSizeCtrl->Enable(false);
+               myNumSectorCtrl->ChangeValue("2880");
+               myNumSectorCtrl->Enable(false);
+               mySizeUnitCtrl->Enable(false);
+               mySizeCtrl->Enable(false);
+               break;
+       };
+       evaluateSize();
+
+       if (myAutoStartSectorCtrl->IsChecked())
+       {
+               std::stringstream ss; ss << myAutoStartSector;
+               myStartSDSectorCtrl->ChangeValue(ss.str());
+       }
+
        uint32_t startSDsector;
        {
                conv << myStartSDSectorCtrl->GetValue();
@@ -348,21 +456,6 @@ TargetPanel::evaluate()
                mySerialMsg->SetLabelMarkup("");
        }
 
-       bool enabled = myEnableCtrl->IsChecked();
-       {
-               myScsiIdCtrl->Enable(enabled);
-               myParityCtrl->Enable(enabled);
-               myUnitAttCtrl->Enable(enabled);
-               myStartSDSectorCtrl->Enable(enabled);
-               mySectorSizeCtrl->Enable(enabled);
-               myNumSectorCtrl->Enable(enabled);
-               mySizeCtrl->Enable(enabled);
-               mySizeUnitCtrl->Enable(enabled);
-               myVendorCtrl->Enable(enabled);
-               myProductCtrl->Enable(enabled);
-               myRevisionCtrl->Enable(enabled);
-               mySerialCtrl->Enable(enabled);
-       }
        return valid || !enabled;
 }
 
@@ -376,49 +469,51 @@ TargetPanel::onInput(EvtType& event)
 void
 TargetPanel::onSizeInput(wxCommandEvent& event)
 {
-       if (event.GetId() == ID_numSectorCtrl)
-       {
-               uint32_t numSectors;
-               std::stringstream conv;
-               conv << myNumSectorCtrl->GetValue();
-               conv >> numSectors;
-
-               conv.str(""); conv.clear();
-
-               if (conv)
-               {
-                       uint64_t bytes =
-                               uint64_t(numSectors) *
-                                       CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
-
-                       if (bytes >= 1024 * 1024 * 1024)
-                       {
-                               conv << (bytes / (1024.0 * 1024 * 1024));
-                               mySizeUnitCtrl->SetSelection(UNIT_GB);
-                       }
-                       else if (bytes >= 1024 * 1024)
-                       {
-                               conv << (bytes / (1024.0 * 1024));
-                               mySizeUnitCtrl->SetSelection(UNIT_MB);
-                       }
-                       else
-                       {
-                               conv << (bytes / 1024.0);
-                               mySizeUnitCtrl->SetSelection(UNIT_KB);
-                       }
-                       mySizeCtrl->ChangeValue(conv.str());
-               }
-       }
-       else
+       if (event.GetId() != ID_numSectorCtrl)
        {
                std::stringstream ss;
                ss << convertUnitsToSectors().first;
                myNumSectorCtrl->ChangeValue(ss.str());
        }
-
+       evaluateSize();
        onInput(event); // propagate
 }
 
+void
+TargetPanel::evaluateSize()
+{
+       uint32_t numSectors;
+       std::stringstream conv;
+       conv << myNumSectorCtrl->GetValue();
+       conv >> numSectors;
+
+       conv.str(""); conv.clear();
+
+       if (conv)
+       {
+               uint64_t bytes =
+                       uint64_t(numSectors) *
+                               CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
+
+               if (bytes >= 1024 * 1024 * 1024)
+               {
+                       conv << (bytes / (1024.0 * 1024 * 1024));
+                       mySizeUnitCtrl->SetSelection(UNIT_GB);
+               }
+               else if (bytes >= 1024 * 1024)
+               {
+                       conv << (bytes / (1024.0 * 1024));
+                       mySizeUnitCtrl->SetSelection(UNIT_MB);
+               }
+               else
+               {
+                       conv << (bytes / 1024.0);
+                       mySizeUnitCtrl->SetSelection(UNIT_KB);
+               }
+               mySizeCtrl->ChangeValue(conv.str());
+       }
+}
+
 std::pair<uint32_t, bool>
 TargetPanel::convertUnitsToSectors() const
 {
@@ -471,9 +566,13 @@ TargetPanel::getConfig() const
                config.scsiId = config.scsiId | CONFIG_TARGET_ENABLED;
        }
 
+       config.deviceType = myDeviceTypeCtrl->GetSelection();
+
        config.flags =
                (myParityCtrl->IsChecked() ? CONFIG_ENABLE_PARITY : 0) |
-               (myUnitAttCtrl->IsChecked() ? CONFIG_ENABLE_UNIT_ATTENTION : 0);
+               (myUnitAttCtrl->IsChecked() ? CONFIG_ENABLE_UNIT_ATTENTION : 0) |
+               (myScsi2Ctrl->IsChecked() ? CONFIG_ENABLE_SCSI2 : 0) |
+               (myGlitchCtrl->IsChecked() ? CONFIG_DISABLE_GLITCH : 0);
 
        auto startSDSector = CtrlGetValue<uint32_t>(myStartSDSectorCtrl);
        config.sdSectorStart = startSDSector.first;
@@ -503,12 +602,17 @@ TargetPanel::setConfig(const TargetConfig& config)
        myScsiIdCtrl->SetValue(config.scsiId & CONFIG_TARGET_ID_BITS);
        myEnableCtrl->SetValue(config.scsiId & CONFIG_TARGET_ENABLED);
 
+       myDeviceTypeCtrl->SetSelection(config.deviceType);
+
        myParityCtrl->SetValue(config.flags & CONFIG_ENABLE_PARITY);
        myUnitAttCtrl->SetValue(config.flags & CONFIG_ENABLE_UNIT_ATTENTION);
+       myScsi2Ctrl->SetValue(config.flags & CONFIG_ENABLE_SCSI2);
+       myGlitchCtrl->SetValue(config.flags & CONFIG_DISABLE_GLITCH);
 
        {
                std::stringstream ss; ss << config.sdSectorStart;
                myStartSDSectorCtrl->ChangeValue(ss.str());
+               myAutoStartSectorCtrl->SetValue(0);
        }
 
        {
@@ -586,3 +690,10 @@ TargetPanel::setSDSectorOverlap(bool overlap)
                myStartSDSectorMsg->SetLabelMarkup("");
        }
 }
+
+void
+TargetPanel::setAutoStartSector(uint32_t start)
+{
+       myAutoStartSector = start;
+}
+