Pārlūkot izejas kodu

Merge pull request #335 from ZuluSCSI/device-presets

Fix GD32 DMA TIMER PhyMode bug & add further support for ZuluSCSI V1.2
Alex Perez 2 gadi atpakaļ
vecāks
revīzija
5cfd2bab59

+ 16 - 15
lib/ZuluSCSI_platform_GD32F205/platform_hw_config.cpp

@@ -24,14 +24,10 @@
 #include "platform_hw_config.h"
 #include <ZuluSCSI_config.h>
 #include <ZuluSCSI_log.h>
+#include <ZuluSCSI_settings.h>
 
 HardwareConfig g_hw_config;
 
-S2S_CFG_TYPE hw_config_selected_device()
-{
-    return g_hw_config.device_type();
-};
-
 bool hw_config_is_active()
 {
     return g_hw_config.is_active();
@@ -63,37 +59,40 @@ void HardwareConfig::init_state(bool is_active)
 {
     m_is_active = is_active;
     m_scsi_id = (gpio_input_port_get(DIPSW_SCSI_ID_BIT_PORT) & DIPSW_SCSI_ID_BIT_PINS) >> DIPSW_SCSI_ID_BIT_SHIFT;
+    m_device_preset = DEV_PRESET_NONE;
     logmsg("SCSI ID set via DIP switch to ", m_scsi_id);
-    
+    scsi_device_settings_t &cfg_dev = *g_scsi_settings.getDevice(m_scsi_id);
+
     uint8_t rotary_select = (gpio_input_port_get(DIPROT_DEVICE_SEL_BIT_PORT) & DIPROT_DEVICE_SEL_BIT_PINS) >> DIPROT_DEVICE_SEL_BIT_SHIFT;
     switch (rotary_select)
     {
     case 0:
-        m_device_type = S2S_CFG_FIXED;
+         cfg_dev.deviceType = S2S_CFG_FIXED;
     break;
     case 1:
-        m_device_type = S2S_CFG_OPTICAL;
+        cfg_dev.deviceType = S2S_CFG_OPTICAL;
     break;
     case 2:
-        m_device_type = S2S_CFG_FLOPPY_14MB;
+        cfg_dev.deviceType = S2S_CFG_FLOPPY_14MB;
     break;
     case 3:
-        m_device_type = S2S_CFG_REMOVABLE;
+        cfg_dev.deviceType = S2S_CFG_REMOVABLE;
     break;
     case 4:
-        m_device_type = S2S_CFG_MO;
+        cfg_dev.deviceType = S2S_CFG_MO;
     break;
     case 5:
-        m_device_type = S2S_CFG_FIXED;
+        m_device_preset = DEV_PRESET_ST32430N;
+        cfg_dev.deviceType = S2S_CFG_FIXED;
     break;
     case 6:
-        m_device_type = S2S_CFG_SEQUENTIAL;
+        cfg_dev.deviceType = S2S_CFG_SEQUENTIAL;
     break;
     default:
-        m_device_type = S2S_CFG_FIXED;
+        cfg_dev.deviceType = S2S_CFG_FIXED;
     }
     
-    if (m_device_type == S2S_CFG_OPTICAL)
+    if (cfg_dev.deviceType == S2S_CFG_OPTICAL)
     {
         m_blocksize = DEFAULT_BLOCKSIZE_OPTICAL;
     }
@@ -101,6 +100,8 @@ void HardwareConfig::init_state(bool is_active)
     {
         m_blocksize = RAW_FALLBACK_BLOCKSIZE;
     }
+
+//    initDeviceSettingsPreset(m_scsi_id, m_device_preset);
 }
 
 #endif // ZULUSCSI_HARDWARE_CONFIG

+ 6 - 3
lib/ZuluSCSI_platform_GD32F205/platform_hw_config.h

@@ -26,6 +26,7 @@
 
 #pragma once
 #include <scsi2sd.h>
+#include <ZuluSCSI_settings.h>
 
 // C wrappers
 #ifdef __cplusplus
@@ -54,15 +55,17 @@ public:
     // get the device type
     // @returns the device type
     const S2S_CFG_TYPE& device_type() const {return m_device_type;}
-    const uint8_t& scsi_id()    const {return m_scsi_id;}
-    const bool& is_active()     const {return m_is_active;}
-    const int blocksize()       const {return m_blocksize;}
+    const uint8_t& scsi_id()          const {return m_scsi_id;}
+    const bool& is_active()           const {return m_is_active;}
+    const int blocksize()             const {return m_blocksize;}
+    const scsi_device_preset_t device_preset() const {return m_device_preset;}
 
 protected:
     S2S_CFG_TYPE m_device_type;
     uint8_t m_scsi_id;
     bool m_is_active;
     int m_blocksize;
+    scsi_device_preset_t m_device_preset;
 };
 
 

+ 2 - 3
lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp

@@ -33,6 +33,7 @@
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 
 #include <scsi2sd.h>
@@ -154,10 +155,8 @@ static void selectPhyMode()
 {
     int oldmode = g_scsi_phy_mode;
 
-    int default_mode = PHY_MODE_BEST_AVAILABLE;
-
     // Read overriding setting from configuration file
-    int wanted_mode = ini_getl("SCSI", "PhyMode", default_mode, CONFIGFILE);
+    int wanted_mode = g_scsi_settings.getSystem()->phyMode;
 
     // Default: software GPIO bitbang, available on all revisions
     g_scsi_phy_mode = PHY_MODE_PIO;

+ 2 - 2
lib/ZuluSCSI_platform_GD32F205/scsi_accel_dma.cpp

@@ -386,10 +386,10 @@ extern "C" void SCSI_TIMER_DMACHB_IRQ()
         else
         {
             // Wait for final ACK to go low, shouldn't take long.
-            int maxwait = 10000;
+            uint32_t start = millis();
             while (TIMER_CNT(SCSI_TIMER) < 1)
             {
-                if (maxwait-- < 0)
+                if ((uint32_t)(millis() - start) > 500)
                 {
                     logmsg("SCSI_TIMER_DMACHB_IRQ: timeout waiting for final ACK");
                     break;

+ 2 - 1
lib/ZuluSCSI_platform_GD32F450/scsiPhy.cpp

@@ -33,6 +33,7 @@
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 
 #include <scsi2sd.h>
@@ -152,7 +153,7 @@ static void selectPhyMode()
     int default_mode = PHY_MODE_BEST_AVAILABLE;
 
     // Read overriding setting from configuration file
-    int wanted_mode = ini_getl("SCSI", "PhyMode", default_mode, CONFIGFILE);
+    int wanted_mode = getSystemSettings()->deviceType;
 
     // Default: software GPIO bitbang, available on all revisions
     g_scsi_phy_mode = PHY_MODE_PIO;

+ 1 - 1
platformio.ini

@@ -166,7 +166,7 @@ build_flags =
     -DZULUSCSI_DAYNAPORT
 ; These take a large portion of the SRAM and can be adjusted
     -DLOGBUFSIZE=8192
-    -DPREFETCH_BUFFER_SIZE=8192
+    -DPREFETCH_BUFFER_SIZE=6144
     -DSCSI2SD_BUFFER_SIZE=57344
     ; This controls the depth of 2 x NETWORK_PACKET_MAX_SIZE (1520 bytes)
     ; For example a queue size of 10 would be 10 x 2 x 1520 = 30400 bytes

+ 3 - 2
src/ImageBackingStore.cpp

@@ -25,6 +25,7 @@
 #include <ZuluSCSI_platform.h>
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 #include <strings.h>
 #include <string.h>
@@ -65,7 +66,7 @@ ImageBackingStore::ImageBackingStore(const char *filename, uint32_t scsi_block_s
         uint32_t sectorCount = SD.card()->sectorCount();
         if (m_endsector >= sectorCount)
         {
-            logmsg("Limiting RAW image mapping to SD card sector count: ", (int)sectorCount);
+            logmsg("---- Limiting RAW image mapping to SD card sector count: ", (int)sectorCount);
             m_endsector = sectorCount - 1;
         }
     }
@@ -113,7 +114,7 @@ ImageBackingStore::ImageBackingStore(const char *filename, uint32_t scsi_block_s
                 // If the drive was formatted using those versions, you may have problems accessing it with newer firmware.
                 // The old behavior can be restored with setting  [SCSI] UseFATAllocSize = 1 in config file.
 
-                if (ini_getbool("SCSI", "UseFATAllocSize", 0, CONFIGFILE))
+                if (g_scsi_settings.getSystem()->useFATAllocSize)
                 {
                     sectorcount = allocsize;
                 }

+ 2 - 1
src/QuirksCheck.cpp

@@ -24,6 +24,7 @@
 #include <minIni.h>
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_log.h"
+#include "ZuluSCSI_settings.h"
 #include "QuirksCheck.h"
 #include <assert.h>
 #include <stdint.h>
@@ -84,7 +85,7 @@ static bool isValidMacintoshImage(image_config_t *img)
 static void macQuirksSanityCheck(image_config_t *img)
 {
 
-    if(ini_getbool("SCSI", "DisableMacSanityCheck", false, CONFIGFILE))
+    if(g_scsi_settings.getDevice(img->scsiId & 7)->disableMacSanityCheck)
     {
         dbgmsg("---- Skipping Mac sanity check due to DisableMacSanityCheck");
         return;

+ 20 - 9
src/ZuluSCSI.cpp

@@ -53,7 +53,7 @@
 #include "ZuluSCSI_platform.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
-#include "ZuluSCSI_presets.h"
+#include "ZuluSCSI_settings.h"
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_initiator.h"
 #include "ROMDrive.h"
@@ -502,7 +502,6 @@ bool findHDDImages()
         {
           logmsg("-- Loading ROM drive from ", fullname, " for id:", id);
           imageReady = scsiDiskProgramRomDrive(fullname, id, blk, type);
-          
           if (imageReady)
           {
             foundImage = true;
@@ -511,6 +510,11 @@ bool findHDDImages()
         else if(id < NUM_SCSIID && lun < NUM_SCSILUN) {
           logmsg("-- Opening ", fullname, " for id:", id, " lun:", lun);
 
+          if (g_scsi_settings.getDevicePreset(id) != DEV_PRESET_NONE)
+          {
+              logmsg("---- Using device preset: ", g_scsi_settings.getDevicePresetName(id));
+          }
+
           imageReady = scsiDiskOpenHDDImage(id, fullname, id, lun, blk, type);
           if(imageReady)
           {
@@ -643,11 +647,18 @@ static void reinitSCSI()
   if (g_hw_config.is_active())
   {
     bool success;
+    uint8_t scsiId = g_hw_config.scsi_id();
+    g_scsi_settings.initDevicePreset(scsiId, g_hw_config.device_preset());
+
     logmsg("Direct/Raw mode enabled, using hardware switches for configuration");
-    success = scsiDiskOpenHDDImage(g_hw_config.scsi_id(), "RAW:0:0xFFFFFFFF", g_hw_config.scsi_id(), 0,
+    success = scsiDiskOpenHDDImage(scsiId, "RAW:0:0xFFFFFFFF",scsiId, 0,
                                    g_hw_config.blocksize(), g_hw_config.device_type());
     if (success)
     {
+      if (g_scsi_settings.getDevicePreset(scsiId) != DEV_PRESET_NONE)
+      {
+        logmsg("---- Using device preset: ", g_scsi_settings.getDevicePresetName(scsiId));
+      }
       blinkStatus(BLINK_STATUS_OK);
     }
     delay(250);
@@ -735,17 +746,17 @@ extern "C" void zuluscsi_setup(void)
     
     char presetName[32];
     ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(presetName);
-    int boot_delay_ms = ini_getl("SCSI", "InitPreDelay", defaults.initPreDelay, CONFIGFILE);
-
+    scsi_system_settings_t *cfg = g_scsi_settings.initSystem(presetName);
+    int boot_delay_ms = cfg->initPreDelay;
     if (boot_delay_ms > 0)
     {
-    logmsg("Pre SCSI init boot delay in millis: ", boot_delay_ms);
+      logmsg("Pre SCSI init boot delay in millis: ", boot_delay_ms);
       delay(boot_delay_ms);
     }
     reinitSCSI();
-
-    boot_delay_ms = ini_getl("SCSI", "InitPostDelay", 0, CONFIGFILE);
+    
+    
+    boot_delay_ms = cfg->initPostDelay;
     if (boot_delay_ms > 0)
     {
       logmsg("Post SCSI init boot delay in millis: ", boot_delay_ms);

+ 95 - 252
src/ZuluSCSI_disk.cpp

@@ -30,7 +30,7 @@
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
-#include "ZuluSCSI_presets.h"
+#include "ZuluSCSI_settings.h"
 #ifdef ENABLE_AUDIO_OUTPUT
 #include "ZuluSCSI_audio.h"
 #endif
@@ -193,46 +193,6 @@ void scsiDiskCloseSDCardImages()
     }
 }
 
-// Verify format conformance to SCSI spec:
-// - Empty bytes filled with 0x20 (space)
-// - Only values 0x20 to 0x7E
-// - Left alignment for vendor/product/revision, right alignment for serial.
-static void formatDriveInfoField(char *field, int fieldsize, bool align_right)
-{
-    if (align_right)
-    {
-        // Right align and trim spaces on either side
-        int dst = fieldsize - 1;
-        for (int src = fieldsize - 1; src >= 0; src--)
-        {
-            char c = field[src];
-            if (c < 0x20 || c > 0x7E) c = 0x20;
-            if (c != 0x20 || dst != fieldsize - 1)
-            {
-                field[dst--] = c;
-            }
-        }
-        while (dst >= 0)
-        {
-            field[dst--] = 0x20;
-        }
-    }
-    else
-    {
-        // Left align, preserve spaces in case config tries to manually right-align
-        int dst = 0;
-        for (int src = 0; src < fieldsize; src++)
-        {
-            char c = field[src];
-            if (c < 0x20 || c > 0x7E) c = 0x20;
-            field[dst++] = c;
-        }
-        while (dst < fieldsize)
-        {
-            field[dst++] = 0x20;
-        }
-    }
-}
 
 // remove path and extension from filename
 void extractFileName(const char* path, char* output) {
@@ -265,119 +225,47 @@ void setNameFromImage(image_config_t &img, const char *filename) {
     strncpy(img.prodId, image_name+8, 8);
 }
 
-// Set default drive vendor / product info after the image file
-// is loaded and the device type is known.
-static void setDefaultDriveInfo(int target_idx)
+// Load values for target image configuration from given section if they exist.
+// Otherwise keep current settings.
+static void scsiDiskSetImageConfig(uint8_t target_idx)
 {
     image_config_t &img = g_DiskImages[target_idx];
+    scsi_system_settings_t *devSys = g_scsi_settings.getSystem();
+    scsi_device_settings_t *devCfg = g_scsi_settings.getDevice(target_idx);
+    img.scsiId = target_idx;
+    memset(img.vendor, 0, sizeof(img.vendor));
+    memset(img.prodId, 0, sizeof(img.prodId));
+    memset(img.revision, 0, sizeof(img.revision));
+    memset(img.serial, 0, sizeof(img.serial));
 
-    static const char *driveinfo_fixed[4]     = DRIVEINFO_FIXED;
-    static const char *driveinfo_removable[4] = DRIVEINFO_REMOVABLE;
-    static const char *driveinfo_optical[4]   = DRIVEINFO_OPTICAL;
-    static const char *driveinfo_floppy[4]    = DRIVEINFO_FLOPPY;
-    static const char *driveinfo_magopt[4]    = DRIVEINFO_MAGOPT;
-    static const char *driveinfo_network[4]   = DRIVEINFO_NETWORK;
-    static const char *driveinfo_tape[4]      = DRIVEINFO_TAPE;
-
-    static const char *apl_driveinfo_fixed[4]     = APPLE_DRIVEINFO_FIXED;
-    static const char *apl_driveinfo_removable[4] = APPLE_DRIVEINFO_REMOVABLE;
-    static const char *apl_driveinfo_optical[4]   = APPLE_DRIVEINFO_OPTICAL;
-    static const char *apl_driveinfo_floppy[4]    = APPLE_DRIVEINFO_FLOPPY;
-    static const char *apl_driveinfo_magopt[4]    = APPLE_DRIVEINFO_MAGOPT;
-    static const char *apl_driveinfo_network[4]   = APPLE_DRIVEINFO_NETWORK;
-    static const char *apl_driveinfo_tape[4]      = APPLE_DRIVEINFO_TAPE;
-
-    const char **driveinfo = NULL;
-
-    if (img.quirks == S2S_CFG_QUIRKS_APPLE)
-    {
-        // Use default drive IDs that are recognized by Apple machines
-        switch (img.deviceType)
-        {
-            case S2S_CFG_FIXED:         driveinfo = apl_driveinfo_fixed; break;
-            case S2S_CFG_REMOVABLE:     driveinfo = apl_driveinfo_removable; break;
-            case S2S_CFG_OPTICAL:       driveinfo = apl_driveinfo_optical; break;
-            case S2S_CFG_FLOPPY_14MB:   driveinfo = apl_driveinfo_floppy; break;
-            case S2S_CFG_MO:            driveinfo = apl_driveinfo_magopt; break;
-            case S2S_CFG_NETWORK:       driveinfo = apl_driveinfo_network; break;
-            case S2S_CFG_SEQUENTIAL:    driveinfo = apl_driveinfo_tape; break;
-            default:                    driveinfo = apl_driveinfo_fixed; break;
-        }
-    }
-    else
-    {
-        // Generic IDs
-        switch (img.deviceType)
-        {
-            case S2S_CFG_FIXED:         driveinfo = driveinfo_fixed; break;
-            case S2S_CFG_REMOVABLE:     driveinfo = driveinfo_removable; break;
-            case S2S_CFG_OPTICAL:       driveinfo = driveinfo_optical; break;
-            case S2S_CFG_FLOPPY_14MB:   driveinfo = driveinfo_floppy; break;
-            case S2S_CFG_MO:            driveinfo = driveinfo_magopt; break;
-            case S2S_CFG_NETWORK:       driveinfo = driveinfo_network; break;
-            case S2S_CFG_SEQUENTIAL:    driveinfo = driveinfo_tape; break;
-            default:                    driveinfo = driveinfo_fixed; break;
-        }
-    }
-
-    if (img.vendor[0] == '\0')
-    {
-        memset(img.vendor, 0, sizeof(img.vendor));
-        strncpy(img.vendor, driveinfo[0], sizeof(img.vendor));
-    }
-
-    if (img.prodId[0] == '\0')
-    {
-        memset(img.prodId, 0, sizeof(img.prodId));
-        strncpy(img.prodId, driveinfo[1], sizeof(img.prodId));
-    }
-
-    if (img.revision[0] == '\0')
-    {
-        memset(img.revision, 0, sizeof(img.revision));
-        strncpy(img.revision, driveinfo[2], sizeof(img.revision));
-    }
-
-    if (img.serial[0] == '\0')
-    {
-        memset(img.serial, 0, sizeof(img.serial));
-        strncpy(img.serial, driveinfo[3], sizeof(img.serial));
-    }
-
-    if (img.serial[0] == '\0')
-    {
-        // Use SD card serial number
-        cid_t sd_cid;
-        uint32_t sd_sn = 0;
-        if (SD.card()->readCID(&sd_cid))
-        {
-            sd_sn = sd_cid.psn();
-        }
-
-        memset(img.serial, 0, sizeof(img.serial));
-        const char *nibble = "0123456789ABCDEF";
-        img.serial[0] = nibble[(sd_sn >> 28) & 0xF];
-        img.serial[1] = nibble[(sd_sn >> 24) & 0xF];
-        img.serial[2] = nibble[(sd_sn >> 20) & 0xF];
-        img.serial[3] = nibble[(sd_sn >> 16) & 0xF];
-        img.serial[4] = nibble[(sd_sn >> 12) & 0xF];
-        img.serial[5] = nibble[(sd_sn >>  8) & 0xF];
-        img.serial[6] = nibble[(sd_sn >>  4) & 0xF];
-        img.serial[7] = nibble[(sd_sn >>  0) & 0xF];
-    }
-
-    int rightAlign = img.rightAlignStrings;
+    img.deviceType = devCfg->deviceType;
+    img.deviceTypeModifier = devCfg->deviceTypeModifier;
+    img.sectorsPerTrack = devCfg->sectorsPerTrack;
+    img.headsPerCylinder = devCfg->headsPerCylinder;
+    img.quirks = devSys->quirks;
+    img.rightAlignStrings = devCfg->rightAlignStrings;
+    img.name_from_image = devCfg->nameFromImage;
+    img.prefetchbytes = devCfg->prefetchBytes;
+    img.reinsert_on_inquiry = devCfg->reinsertOnInquiry;
+    img.reinsert_after_eject = devCfg->reinsertAfterEject;
+    img.ejectButton = devCfg->ejectButton;
+#ifdef ENABLE_AUDIO_OUTPUT
+    uint16_t vol = devCfg->vol;
+    // Set volume on both channels
+    audio_set_volume(target_idx, (vol << 8) | vol);
+#endif
 
-    formatDriveInfoField(img.vendor, sizeof(img.vendor), rightAlign);
-    formatDriveInfoField(img.prodId, sizeof(img.prodId), rightAlign);
-    formatDriveInfoField(img.revision, sizeof(img.revision), rightAlign);
-    formatDriveInfoField(img.serial, sizeof(img.serial), true);
+    memcpy(img.vendor, devCfg->vendor, sizeof(img.vendor));
+    memcpy(img.prodId, devCfg->prodId, sizeof(img.prodId));
+    memcpy(img.revision, devCfg->revision, sizeof(img.revision));
+    memcpy(img.serial, devCfg->serial, sizeof(img.serial));
 }
 
 bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int scsi_lun, int blocksize, S2S_CFG_TYPE type)
 {
     image_config_t &img = g_DiskImages[target_idx];
     img.cuesheetfile.close();
+    scsiDiskSetImageConfig(target_idx);
     img.file = ImageBackingStore(filename, blocksize);
 
     if (img.file.isOpen())
@@ -445,9 +333,6 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
             img.deviceType = S2S_CFG_SEQUENTIAL;
         }
 
-#ifdef PLATFORM_CONFIG_HOOK
-        PLATFORM_CONFIG_HOOK(&img);
-#endif
         quirksCheck(&img);
 
         if (img.name_from_image)
@@ -456,8 +341,6 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
             logmsg("---- Vendor / product id set from image file name");
         }
 
-        setDefaultDriveInfo(target_idx);
-
         if (type == S2S_CFG_NETWORK)
         {
             // prefetch not used, skip emitting log message
@@ -563,30 +446,6 @@ bool scsiDiskFilenameValid(const char* name)
     return true;
 }
 
-// Set target configuration to default values
-static void scsiDiskConfigDefaults(int target_idx)
-{
-    // Get default values from system preset, if any
-    char presetName[32];
-    ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(presetName);
-
-    image_config_t &img = g_DiskImages[target_idx];
-    img.scsiId = target_idx;
-    img.deviceType = S2S_CFG_FIXED;
-    img.deviceTypeModifier = defaults.deviceTypeModifier;
-    img.sectorsPerTrack = defaults.sectorsPerTrack;
-    img.headsPerCylinder = defaults.headsPerCylinder;
-    img.quirks = defaults.quirks;
-    img.prefetchbytes = defaults.prefetchBytes;
-    img.reinsert_on_inquiry = true;
-    img.reinsert_after_eject = true;
-    memset(img.vendor, 0, sizeof(img.vendor));
-    memset(img.prodId, 0, sizeof(img.prodId));
-    memset(img.revision, 0, sizeof(img.revision));
-    memset(img.serial, 0, sizeof(img.serial));
-}
-
 static void scsiDiskCheckDir(char * dir_name, int target_idx, image_config_t* img, S2S_CFG_TYPE type, const char* type_name)
 {
     if (SD.exists(dir_name))
@@ -604,79 +463,52 @@ static void scsiDiskCheckDir(char * dir_name, int target_idx, image_config_t* im
     }
 }
 
+
 // Load values for target configuration from given section if they exist.
 // Otherwise keep current settings.
-static void scsiDiskLoadConfig(int target_idx, const char *section)
+static void scsiDiskSetConfig(int target_idx)
 {
+  
     image_config_t &img = g_DiskImages[target_idx];
-    img.deviceType = ini_getl(section, "Type", img.deviceType, CONFIGFILE);
-    img.deviceTypeModifier = ini_getl(section, "TypeModifier", img.deviceTypeModifier, CONFIGFILE);
-    img.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", img.sectorsPerTrack, CONFIGFILE);
-    img.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", img.headsPerCylinder, CONFIGFILE);
-    img.quirks = ini_getl(section, "Quirks", img.quirks, CONFIGFILE);
-    img.rightAlignStrings = ini_getbool(section, "RightAlignStrings", 0, CONFIGFILE);
-    img.name_from_image = ini_getbool(section, "NameFromImage", 0, CONFIGFILE);
-    img.prefetchbytes = ini_getl(section, "PrefetchBytes", img.prefetchbytes, CONFIGFILE);
-    img.reinsert_on_inquiry = ini_getbool(section, "ReinsertCDOnInquiry", img.reinsert_on_inquiry, CONFIGFILE);
-    img.reinsert_after_eject = ini_getbool(section, "ReinsertAfterEject", img.reinsert_after_eject, CONFIGFILE);
-    img.ejectButton = ini_getl(section, "EjectButton", 0, CONFIGFILE);
-#ifdef ENABLE_AUDIO_OUTPUT
-    uint16_t vol = ini_getl(section, "CDAVolume", DEFAULT_VOLUME_LEVEL, CONFIGFILE) & 0xFF;
-    // Set volume on both channels
-    audio_set_volume(target_idx, (vol << 8) | vol);
-#endif
-
-    char tmp[32];
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.vendor, tmp, sizeof(img.vendor));
-
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Product", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.prodId, tmp, sizeof(img.prodId));
+    img.scsiId = target_idx;
 
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.revision, tmp, sizeof(img.revision));
+    scsiDiskSetImageConfig(target_idx);
 
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Serial", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.serial, tmp, sizeof(img.serial));
+    char section[6] = "SCSI0";
+    section[4] += target_idx;
+    char tmp[32];
 
-    if (strlen(section) == 5 && strncmp(section, "SCSI", 4) == 0) // allow within target [SCSIx] blocks only
+    ini_gets(section, "ImgDir", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
     {
-        ini_gets(section, "ImgDir", "", tmp, sizeof(tmp), CONFIGFILE);
-        if (tmp[0])
-        {
-            logmsg("SCSI", target_idx, " using image directory '", tmp, "'");
-            img.image_directory = true;
-        }
-        else
-        {
-            strcpy(tmp, "HD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FIXED, "disk");
+        logmsg("SCSI", target_idx, " using image directory '", tmp, "'");
+        img.image_directory = true;
+    }
+    else
+    {
+        strcpy(tmp, "HD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FIXED, "disk");
 
-            strcpy(tmp, "CD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_OPTICAL, "optical");
+        strcpy(tmp, "CD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_OPTICAL, "optical");
 
-            strcpy(tmp, "RE0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_REMOVABLE, "removable");
+        strcpy(tmp, "RE0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_REMOVABLE, "removable");
 
-            strcpy(tmp, "MO0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_MO, "magneto-optical");
+        strcpy(tmp, "MO0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_MO, "magneto-optical");
 
-            strcpy(tmp, "TP0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_SEQUENTIAL, "tape");
+        strcpy(tmp, "TP0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_SEQUENTIAL, "tape");
 
-            strcpy(tmp, "FD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FLOPPY_14MB, "floppy");
-        }
+        strcpy(tmp, "FD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FLOPPY_14MB, "floppy");
     }
 }
 
@@ -875,17 +707,30 @@ int scsiDiskGetNextImageName(image_config_t &img, char *buf, size_t buflen)
 
 void scsiDiskLoadConfig(int target_idx)
 {
+    // Get values from system preset, if any
+    char presetName[32] = {};
+
+    // Get values from device preset, if any
     char section[6] = "SCSI0";
     section[4] = '0' + target_idx;
-
-    // Set default settings
-    scsiDiskConfigDefaults(target_idx);
-
-    // First load global settings
-    scsiDiskLoadConfig(target_idx, "SCSI");
+#ifdef ZULUSCSI_HARDWARE_CONFIG
+    const char *hwDevicePresetName = g_scsi_settings.getDevicePresetName(target_idx);
+    if (g_hw_config.is_active())
+    {
+        if (strlen(hwDevicePresetName) < sizeof(presetName))
+        {
+            strncpy(presetName, hwDevicePresetName, sizeof(presetName) - 1);
+        }
+    }
+    else
+#endif
+    {
+        ini_gets(section, "Device", "", presetName, sizeof(presetName), CONFIGFILE);
+    }
+    g_scsi_settings.initDevicePName(target_idx, presetName);
 
     // Then settings specific to target ID
-    scsiDiskLoadConfig(target_idx, section);
+    scsiDiskSetConfig(target_idx);
 
     // Check if we have image specified by name
     char filename[MAX_FILE_PATH];
@@ -983,7 +828,6 @@ bool scsiDiskCheckAnyNetworkDevicesConfigured()
             return true;
         }
     }
-
     return false;
 }
 
@@ -1008,11 +852,11 @@ void s2s_configInit(S2S_BoardCfg* config)
 
     // Get default values from system preset, if any
     ini_gets("SCSI", "System", "", tmp, sizeof(tmp), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(tmp);
+    scsi_system_settings_t *sysCfg = g_scsi_settings.initSystem(tmp);
 
-    if (defaults.presetName)
+    if (g_scsi_settings.getSystemPreset() != SYS_PRESET_NONE)
     {
-        logmsg("Active configuration (using system preset \"", defaults.presetName, "\"):");
+        logmsg("Active configuration (using system preset \"", g_scsi_settings.getSystemPresetName(), "\"):");
     }
     else
     {
@@ -1023,11 +867,11 @@ void s2s_configInit(S2S_BoardCfg* config)
     memcpy(config->magic, "BCFG", 4);
     config->flags = 0;
     config->startupDelay = 0;
-    config->selectionDelay = ini_getl("SCSI", "SelectionDelay", defaults.selectionDelay, CONFIGFILE);
+    config->selectionDelay = sysCfg->selectionDelay;
     config->flags6 = 0;
     config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;
 
-    int maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", defaults.maxSyncSpeed, CONFIGFILE);
+    int maxSyncSpeed = sysCfg->maxSyncSpeed;
     if (maxSyncSpeed < 5 && config->scsiSpeed > S2S_CFG_SPEED_ASYNC_50)
         config->scsiSpeed = S2S_CFG_SPEED_ASYNC_50;
     else if (maxSyncSpeed < 10 && config->scsiSpeed > S2S_CFG_SPEED_SYNC_5)
@@ -1035,7 +879,7 @@ void s2s_configInit(S2S_BoardCfg* config)
 
     logmsg("-- SelectionDelay = ", (int)config->selectionDelay);
 
-    if (ini_getbool("SCSI", "EnableUnitAttention", defaults.enableUnitAttention, CONFIGFILE))
+    if (sysCfg->enableUnitAttention)
     {
         logmsg("-- EnableUnitAttention = Yes");
         config->flags |= S2S_CFG_ENABLE_UNIT_ATTENTION;
@@ -1045,7 +889,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableUnitAttention = No");
     }
 
-    if (ini_getbool("SCSI", "EnableSCSI2", defaults.enableSCSI2, CONFIGFILE))
+    if (sysCfg->enableSCSI2)
     {
         logmsg("-- EnableSCSI2 = Yes");
         config->flags |= S2S_CFG_ENABLE_SCSI2;
@@ -1055,7 +899,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableSCSI2 = No");
     }
 
-    if (ini_getbool("SCSI", "EnableSelLatch", defaults.enableSelLatch, CONFIGFILE))
+    if (sysCfg->enableSelLatch)
     {
         logmsg("-- EnableSelLatch = Yes");
         config->flags |= S2S_CFG_ENABLE_SEL_LATCH;
@@ -1065,7 +909,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableSelLatch = No");
     }
 
-    if (ini_getbool("SCSI", "MapLunsToIDs", defaults.mapLunsToIDs, CONFIGFILE))
+    if (sysCfg->mapLunsToIDs)
     {
         logmsg("-- MapLunsToIDs = Yes");
         config->flags |= S2S_CFG_MAP_LUNS_TO_IDS;
@@ -1076,7 +920,7 @@ void s2s_configInit(S2S_BoardCfg* config)
     }
 
 #ifdef PLATFORM_HAS_PARITY_CHECK
-    if (ini_getbool("SCSI", "EnableParity", defaults.enableParity, CONFIGFILE))
+    if (sysCfg->enableParity)
     {
         logmsg("-- EnableParity = Yes");
         config->flags |= S2S_CFG_ENABLE_PARITY;
@@ -1086,7 +930,6 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableParity = No");
     }
 #endif
-
     memset(tmp, 0, sizeof(tmp));
     ini_gets("SCSI", "WiFiMACAddress", "", tmp, sizeof(tmp), CONFIGFILE);
     if (tmp[0])

+ 1 - 2
src/ZuluSCSI_disk.h

@@ -74,9 +74,8 @@ struct image_config_t: public S2S_TargetCfg
     // Cue sheet file for CD-ROM images
     FsFile cuesheetfile;
 
-    // Right-align vendor / product type strings (for Apple)
+    // Right-align vendor / product type strings
     // Standard SCSI uses left alignment
-    // This field uses -1 for default when field is not set in .ini
     int rightAlignStrings;
 
     // Set Vendor / Product Id from image file name

+ 0 - 60
src/ZuluSCSI_presets.cpp

@@ -1,60 +0,0 @@
-#include "ZuluSCSI_presets.h"
-#include "ZuluSCSI_disk.h"
-#include "ZuluSCSI_log.h"
-#include "ZuluSCSI_config.h"
-#include <strings.h>
-
-// Helper function for case-insensitive string compare
-static bool strequals(const char *a, const char *b)
-{
-    return strcasecmp(a, b) == 0;
-}
-
-preset_config_t getSystemPreset(const char *presetName)
-{
-    // Default configuration
-    preset_config_t cfg = {};
-    cfg.quirks = S2S_CFG_QUIRKS_NONE;
-    cfg.deviceTypeModifier = 0;
-    cfg.sectorsPerTrack = 63;
-    cfg.headsPerCylinder = 255;
-    cfg.prefetchBytes = PREFETCH_BUFFER_SIZE;
-
-    cfg.selectionDelay = 255;
-    cfg.maxSyncSpeed = 10;
-    cfg.enableUnitAttention = false;
-    cfg.enableSCSI2 = true;
-    cfg.enableSelLatch = false;
-    cfg.mapLunsToIDs = false;
-    cfg.enableParity = true;
-    cfg.initPreDelay = 0;
-
-    // System-specific defaults
-    if (strequals(presetName, ""))
-    {
-        // Preset name is empty, use default configuration
-    }
-    else if (strequals(presetName, "Mac"))
-    {
-        cfg.presetName = "Mac";
-        cfg.quirks = S2S_CFG_QUIRKS_APPLE;
-    }
-    else if (strequals(presetName, "MacPlus"))
-    {
-        cfg.presetName = "MacPlus";
-        cfg.quirks = S2S_CFG_QUIRKS_APPLE;
-        cfg.enableSelLatch = true;
-        cfg.enableSCSI2 = false;
-        cfg.selectionDelay = 0;
-    }
-    else if (strequals(presetName, "MPC3000"))
-    {
-        cfg.initPreDelay = 600;
-    }
-    else
-    {
-        logmsg("Unknown preset name ", presetName, ", using default settings");
-    }
-
-    return cfg;
-}

+ 0 - 33
src/ZuluSCSI_presets.h

@@ -1,33 +0,0 @@
-// Preset configurations for various system types.
-// Set by "System" config option in config ini.
-
-#pragma once
-
-// The settings set here will be used as defaults but
-// can be overridden by the ini file settings.
-struct preset_config_t {
-    // Informative name of the preset configuration, or NULL for defaults
-    const char *presetName;
-
-    // Default settings that apply per SCSI ID
-    int quirks;
-    int deviceTypeModifier;
-    int sectorsPerTrack;
-    int headsPerCylinder;
-    int prefetchBytes;
-    bool rightAlignStrings;
-    bool reinsertOnInquiry;
-
-    // Default settings that apply to all SCSI IDs
-    int selectionDelay;
-    int maxSyncSpeed;
-    int initPreDelay;
-    bool enableUnitAttention;
-    bool enableSCSI2;
-    bool enableSelLatch;
-    bool mapLunsToIDs;
-    bool enableParity;
-};
-
-// Fetch a preset configuration, or return the default config if unknown system type.
-preset_config_t getSystemPreset(const char *presetName);

+ 429 - 0
src/ZuluSCSI_settings.cpp

@@ -0,0 +1,429 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
+ * 
+ * This file is licensed under the GPL version 3 or any later version.  
+ * It is derived from scsiPhy.c in SCSI2SD V6.
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+
+
+#include "ZuluSCSI_disk.h"
+#include "ZuluSCSI_audio.h"
+#include "ZuluSCSI_log.h"
+#include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
+#include <strings.h>
+#include <minIni.h>
+#include <minIni_cache.h>
+
+// SCSI system and device settings
+ZuluSCSISettings g_scsi_settings;
+
+const char *systemPresetName[] = {"", "Mac", "MacPlus", "MPC3000"};
+const char *devicePresetName[] = {"", "ST32430N"};
+
+// Helper function for case-insensitive string compare
+static bool strequals(const char *a, const char *b)
+{
+    return strcasecmp(a, b) == 0;
+}
+
+// Verify format conformance to SCSI spec:
+// - Empty bytes filled with 0x20 (space)
+// - Only values 0x20 to 0x7E
+// - Left alignment for vendor/product/revision, right alignment for serial.
+static void formatDriveInfoField(char *field, int fieldsize, bool align_right)
+{
+    if (align_right)
+    {
+        // Right align and trim spaces on either side
+        int dst = fieldsize - 1;
+        for (int src = fieldsize - 1; src >= 0; src--)
+        {
+            char c = field[src];
+            if (c < 0x20 || c > 0x7E) c = 0x20;
+            if (c != 0x20 || dst != fieldsize - 1)
+            {
+                field[dst--] = c;
+            }
+        }
+        while (dst >= 0)
+        {
+            field[dst--] = 0x20;
+        }
+    }
+    else
+    {
+        // Left align, preserve spaces in case config tries to manually right-align
+        int dst = 0;
+        for (int src = 0; src < fieldsize; src++)
+        {
+            char c = field[src];
+            if (c < 0x20 || c > 0x7E) c = 0x20;
+            field[dst++] = c;
+        }
+        while (dst < fieldsize)
+        {
+            field[dst++] = 0x20;
+        }
+    }
+}
+
+const char **ZuluSCSISettings::deviceInitST32430N(uint8_t scsiId)
+{
+    static const char *st32430n[4] = {"SEAGATE", devicePresetName[DEV_PRESET_ST32430N], PLATFORM_REVISION, ""};
+    m_dev[scsiId].deviceType = S2S_CFG_FIXED;
+    m_devPreset[scsiId] = DEV_PRESET_ST32430N;
+    return st32430n;
+}
+
+
+void ZuluSCSISettings::setDefaultDriveInfo(uint8_t scsiId, const char *presetName)
+{
+    char section[6] = "SCSI0";
+    section[4] += scsiId;
+
+    scsi_device_settings_t &cfgDev = m_dev[scsiId];
+    scsi_device_settings_t &cfgDefault = m_dev[SCSI_SETTINGS_SYS_IDX];
+
+    static const char *driveinfo_fixed[4]     = DRIVEINFO_FIXED;
+    static const char *driveinfo_removable[4] = DRIVEINFO_REMOVABLE;
+    static const char *driveinfo_optical[4]   = DRIVEINFO_OPTICAL;
+    static const char *driveinfo_floppy[4]    = DRIVEINFO_FLOPPY;
+    static const char *driveinfo_magopt[4]    = DRIVEINFO_MAGOPT;
+    static const char *driveinfo_network[4]   = DRIVEINFO_NETWORK;
+    static const char *driveinfo_tape[4]      = DRIVEINFO_TAPE;
+
+    static const char *apl_driveinfo_fixed[4]     = APPLE_DRIVEINFO_FIXED;
+    static const char *apl_driveinfo_removable[4] = APPLE_DRIVEINFO_REMOVABLE;
+    static const char *apl_driveinfo_optical[4]   = APPLE_DRIVEINFO_OPTICAL;
+    static const char *apl_driveinfo_floppy[4]    = APPLE_DRIVEINFO_FLOPPY;
+    static const char *apl_driveinfo_magopt[4]    = APPLE_DRIVEINFO_MAGOPT;
+    static const char *apl_driveinfo_network[4]   = APPLE_DRIVEINFO_NETWORK;
+    static const char *apl_driveinfo_tape[4]      = APPLE_DRIVEINFO_TAPE;
+
+    const char **driveinfo = NULL;
+    bool known_preset = false;
+    scsi_system_settings_t& cfgSys = m_sys;
+
+
+#ifdef ZULUSCSI_HARDWARE_CONFIG
+    if (g_hw_config.is_active() && g_hw_config.device_preset() ==  DEV_PRESET_NONE)
+    {
+        // empty preset, use default
+        known_preset = true;
+        m_devPreset[scsiId] = DEV_PRESET_NONE;
+    }
+    else if (g_hw_config.is_active() && g_hw_config.device_preset() ==  DEV_PRESET_ST32430N)
+    {
+        driveinfo = deviceInitST32430N(scsiId);
+        known_preset = true;
+    }
+    else
+#endif //ZULUSCSI_HARDWARE_CONFIG
+    if (strequals(devicePresetName[DEV_PRESET_NONE], presetName))
+    {
+        // empty preset, use default
+        known_preset = true;
+        m_devPreset[scsiId] = DEV_PRESET_NONE;
+    }
+    else if (strequals(devicePresetName[DEV_PRESET_ST32430N], presetName))
+    {
+        driveinfo = deviceInitST32430N(scsiId);
+        known_preset = true;
+    }
+
+    if (!known_preset)
+    {
+        m_devPreset[scsiId] = DEV_PRESET_NONE;
+        logmsg("Unknown Device preset name ", presetName, ", using default settings");
+    }
+
+    if (m_devPreset[scsiId] == DEV_PRESET_NONE)
+    {
+            if (cfgSys.quirks == S2S_CFG_QUIRKS_APPLE)
+        {
+            // Use default drive IDs that are recognized by Apple machines
+            switch (cfgDev.deviceType)
+            {
+                case S2S_CFG_FIXED:         driveinfo = apl_driveinfo_fixed; break;
+                case S2S_CFG_REMOVABLE:     driveinfo = apl_driveinfo_removable; break;
+                case S2S_CFG_OPTICAL:       driveinfo = apl_driveinfo_optical; break;
+                case S2S_CFG_FLOPPY_14MB:   driveinfo = apl_driveinfo_floppy; break;
+                case S2S_CFG_MO:            driveinfo = apl_driveinfo_magopt; break;
+                case S2S_CFG_NETWORK:       driveinfo = apl_driveinfo_network; break;
+                case S2S_CFG_SEQUENTIAL:    driveinfo = apl_driveinfo_tape; break;
+                default:                    driveinfo = apl_driveinfo_fixed; break;
+            }
+        }
+        else
+        {
+            // Generic IDs
+            switch (cfgDev.deviceType)
+            {
+                case S2S_CFG_FIXED:         driveinfo = driveinfo_fixed; break;
+                case S2S_CFG_REMOVABLE:     driveinfo = driveinfo_removable; break;
+                case S2S_CFG_OPTICAL:       driveinfo = driveinfo_optical; break;
+                case S2S_CFG_FLOPPY_14MB:   driveinfo = driveinfo_floppy; break;
+                case S2S_CFG_MO:            driveinfo = driveinfo_magopt; break;
+                case S2S_CFG_NETWORK:       driveinfo = driveinfo_network; break;
+                case S2S_CFG_SEQUENTIAL:    driveinfo = driveinfo_tape; break;
+                default:                    driveinfo = driveinfo_fixed; break;
+            }
+        }
+    }
+
+    // If the scsi string has not been set system wide use default scsi string
+    if (!cfgDefault.vendor[0] && driveinfo[0][0])
+        strncpy(cfgDev.vendor, driveinfo[0], sizeof(cfgDev.vendor));
+    if (!cfgDefault.prodId[0] && driveinfo[1][0])
+        strncpy(cfgDev.prodId, driveinfo[1], sizeof(cfgDev.prodId));
+    if (!cfgDefault.revision[0] && driveinfo[2][0])
+        strncpy(cfgDev.revision, driveinfo[2], sizeof(cfgDev.revision));
+    if (!cfgDefault.serial[0] && driveinfo[3][0])
+        strncpy(cfgDev.serial, driveinfo[3], sizeof(cfgDev.serial));
+}
+
+// Read device settings
+static void readIniSCSIDeviceSetting(scsi_device_settings_t &cfg, const char *section)
+{
+    cfg.deviceType = ini_getl(section, "Type", cfg.deviceType, CONFIGFILE);
+    cfg.deviceTypeModifier = ini_getl(section, "TypeModifier", cfg.deviceTypeModifier, CONFIGFILE);
+    cfg.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", cfg.sectorsPerTrack, CONFIGFILE);
+    cfg.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", cfg.headsPerCylinder, CONFIGFILE);
+    cfg.prefetchBytes = ini_getl(section, "PrefetchBytes", cfg.prefetchBytes, CONFIGFILE);
+    cfg.ejectButton = ini_getl(section, "EjectButton", cfg.ejectButton, CONFIGFILE);
+
+    cfg.vol = ini_getl(section, "CDAVolume", cfg.vol, CONFIGFILE) & 0xFF;
+
+    cfg.nameFromImage = ini_getbool(section, "NameFromImage", cfg.nameFromImage, CONFIGFILE);
+    cfg.rightAlignStrings = ini_getbool(section, "RightAlignStrings", cfg.rightAlignStrings , CONFIGFILE);
+    cfg.reinsertOnInquiry = ini_getbool(section, "ReinsertCDOnInquiry", cfg.reinsertOnInquiry, CONFIGFILE);
+    cfg.reinsertAfterEject = ini_getbool(section, "ReinsertAfterEject", cfg.reinsertAfterEject, CONFIGFILE);
+    cfg.disableMacSanityCheck = ini_getbool(section, "DisableMacSanityCheck", cfg.disableMacSanityCheck, CONFIGFILE);
+
+    char tmp[32];
+    ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.vendor, 0, sizeof(cfg.vendor));
+        strncpy(cfg.vendor, tmp, sizeof(cfg.vendor));
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Product", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.prodId, 0, sizeof(cfg.prodId));
+        strncpy(cfg.prodId, tmp, sizeof(cfg.prodId));
+
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.revision, 0, sizeof(cfg.revision));
+        strncpy(cfg.revision, tmp, sizeof(cfg.revision));
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Serial", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.serial, 0, sizeof(cfg.serial));
+        strncpy(cfg.serial, tmp, sizeof(cfg.serial));
+    }
+}
+
+scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
+{
+    scsi_system_settings_t &cfgSys = m_sys;
+    scsi_device_settings_t &cfgDev = m_dev[SCSI_SETTINGS_SYS_IDX];
+    // This is a hack to figure out if apple quirks is on via a dip switch
+    S2S_TargetCfg img;
+
+    img.quirks = S2S_CFG_QUIRKS_NONE;
+    #ifdef PLATFORM_CONFIG_HOOK
+            PLATFORM_CONFIG_HOOK(&img);
+    #endif
+
+    // Default settings for host compatibility 
+    cfgSys.quirks = img.quirks;
+    cfgSys.selectionDelay = 255;
+    cfgSys.maxSyncSpeed = 10;
+    cfgSys.initPreDelay = 0;
+    cfgSys.initPostDelay = 0;
+    cfgSys.phyMode = 0;
+
+    cfgSys.enableUnitAttention = false;
+    cfgSys.enableSCSI2 = true;
+    cfgSys.enableSelLatch = false;
+    cfgSys.mapLunsToIDs = false;
+    cfgSys.enableParity = true;
+    cfgSys.useFATAllocSize = false;
+    
+    // setting set for all or specific devices
+    cfgDev.deviceType = 0;
+    cfgDev.deviceTypeModifier = 0;
+    cfgDev.sectorsPerTrack = 63;
+    cfgDev.headsPerCylinder = 255;
+    cfgDev.prefetchBytes = PREFETCH_BUFFER_SIZE;
+    cfgDev.ejectButton = 0;
+    cfgDev.vol = DEFAULT_VOLUME_LEVEL;
+    
+    cfgDev.nameFromImage = false;
+    cfgDev.rightAlignStrings = false;
+    cfgDev.reinsertOnInquiry = true;
+    cfgDev.reinsertAfterEject = true;
+    cfgDev.disableMacSanityCheck = false;
+
+    // System-specific defaults
+
+    if (strequals(systemPresetName[SYS_PRESET_NONE], ""))
+    {
+        // Preset name is empty, use default configuration
+        m_sysPreset = SYS_PRESET_NONE;
+    }
+    else if (strequals(systemPresetName[SYS_PRESET_MAC], "Mac"))
+    {
+        m_sysPreset = SYS_PRESET_MAC;
+        cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
+    }
+    else if (strequals(systemPresetName[SYS_PRESET_MACPLUS], "MacPlus"))
+    {
+        m_sysPreset = SYS_PRESET_MACPLUS;
+        cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
+        cfgSys.enableSelLatch = true;
+        cfgSys.enableSCSI2 = false;
+        cfgSys.selectionDelay = 0;
+    }
+    else if (strequals(systemPresetName[SYS_PRESET_MPC3000], "MPC3000"))
+    {
+        cfgSys.initPreDelay = 600;
+    }
+    else
+    {
+        m_sysPreset = SYS_PRESET_NONE;
+        logmsg("Unknown System preset name ", presetName, ", using default settings");
+    }
+
+    // Clear SCSI device strings
+    memset(cfgDev.vendor, 0, sizeof(cfgDev.vendor));
+    memset(cfgDev.prodId, 0, sizeof(cfgDev.prodId));
+    memset(cfgDev.revision, 0, sizeof(cfgDev.revision));
+    memset(cfgDev.serial, 0, sizeof(cfgDev.serial));
+
+    // Read default setting overrides from ini file for each SCSI device
+    readIniSCSIDeviceSetting(cfgDev, "SCSI");
+
+    // Read settings from ini file that apply to all SCSI device
+    cfgSys.quirks = ini_getl("SCSI", "Quirks", cfgSys.quirks, CONFIGFILE);
+    cfgSys.selectionDelay = ini_getl("SCSI", "SelectionDelay", cfgSys.selectionDelay, CONFIGFILE);
+    cfgSys.maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", cfgSys.maxSyncSpeed, CONFIGFILE);
+    cfgSys.initPreDelay = ini_getl("SCSI", "InitPreDelay", cfgSys.initPreDelay, CONFIGFILE);
+    cfgSys.initPostDelay = ini_getl("SCSI", "InitPostDelay", cfgSys.initPostDelay, CONFIGFILE);
+    cfgSys.phyMode = ini_getl("SCSI", "PhyMode", cfgSys.phyMode, CONFIGFILE);
+
+    cfgSys.enableUnitAttention = ini_getbool("SCSI", "EnableUnitAttention", cfgSys.enableUnitAttention, CONFIGFILE);
+    cfgSys.enableSCSI2 = ini_getbool("SCSI", "EnableSCSI2", cfgSys.enableSCSI2, CONFIGFILE);
+    cfgSys.enableSelLatch = ini_getbool("SCSI", "EnableSelLatch", cfgSys.enableSelLatch, CONFIGFILE);
+    cfgSys.mapLunsToIDs = ini_getbool("SCSI", "MapLunsToIDs", cfgSys.mapLunsToIDs, CONFIGFILE);
+    cfgSys.enableParity =  ini_getbool("SCSI", "EnableParity", cfgSys.enableParity, CONFIGFILE);
+    cfgSys.useFATAllocSize = ini_getbool("SCSI", "UseFATAllocSize", cfgSys.useFATAllocSize, CONFIGFILE);
+
+    return &cfgSys;
+}
+
+scsi_device_settings_t* ZuluSCSISettings::initDevicePName(uint8_t scsiId, const char *presetName)
+{
+    scsi_device_settings_t& cfg = m_dev[scsiId];
+
+    // Write default configuration from system setting initialization
+    memcpy(&cfg, &m_dev[SCSI_SETTINGS_SYS_IDX], sizeof(cfg));
+    
+    char section[6] = "SCSI0";
+    section[4] += scsiId;
+    setDefaultDriveInfo(scsiId, presetName);
+    readIniSCSIDeviceSetting(cfg, section);
+
+    if (cfg.serial[0] == '\0')
+    {
+        // Use SD card serial number
+        cid_t sd_cid;
+        uint32_t sd_sn = 0;
+        if (SD.card()->readCID(&sd_cid))
+        {
+            sd_sn = sd_cid.psn();
+        }
+
+        memset(cfg.serial, 0, sizeof(cfg.serial));
+        const char *nibble = "0123456789ABCDEF";
+        cfg.serial[0] = nibble[(sd_sn >> 28) & 0xF];
+        cfg.serial[1] = nibble[(sd_sn >> 24) & 0xF];
+        cfg.serial[2] = nibble[(sd_sn >> 20) & 0xF];
+        cfg.serial[3] = nibble[(sd_sn >> 16) & 0xF];
+        cfg.serial[4] = nibble[(sd_sn >> 12) & 0xF];
+        cfg.serial[5] = nibble[(sd_sn >>  8) & 0xF];
+        cfg.serial[6] = nibble[(sd_sn >>  4) & 0xF];
+        cfg.serial[7] = nibble[(sd_sn >>  0) & 0xF];
+    }
+
+
+    formatDriveInfoField(cfg.vendor, sizeof(cfg.vendor), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.prodId, sizeof(cfg.prodId), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.revision, sizeof(cfg.revision), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.serial, sizeof(cfg.serial), true);
+
+    return &cfg;
+}
+
+scsi_device_settings_t *ZuluSCSISettings::initDevicePreset(uint8_t scsiId, const scsi_device_preset_t preset)
+{
+    return initDevicePName(scsiId, devicePresetName[preset]);
+}
+
+
+scsi_system_settings_t *ZuluSCSISettings::getSystem()
+{
+    return &m_sys;
+}
+
+scsi_device_settings_t *ZuluSCSISettings::getDevice(uint8_t scsiId)
+{
+    return &m_dev[scsiId];
+}
+
+scsi_system_preset_t ZuluSCSISettings::getSystemPreset()
+{
+    return m_sysPreset;
+}
+
+const char* ZuluSCSISettings::getSystemPresetName()
+{
+    return systemPresetName[m_sysPreset];
+}
+
+scsi_device_preset_t ZuluSCSISettings::getDevicePreset(uint8_t scsiId)
+{
+    return m_devPreset[scsiId];
+}
+
+const char* ZuluSCSISettings::getDevicePresetName(uint8_t scsiId)
+{
+    return devicePresetName[m_devPreset[scsiId]];
+}

+ 146 - 0
src/ZuluSCSI_settings.h

@@ -0,0 +1,146 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
+ * 
+ * This file is licensed under the GPL version 3 or any later version.  
+ * It is derived from scsiPhy.c in SCSI2SD V6.
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+#ifdef __cplusplus
+
+#include <stdint.h>
+
+// Index 8 is the system defaults
+// Index 0-7 represent device settings
+#define SCSI_SETTINGS_SYS_IDX 8
+
+typedef enum
+{
+    SYS_PRESET_NONE = 0,
+    SYS_PRESET_MAC,
+    SYS_PRESET_MACPLUS,
+    SYS_PRESET_MPC3000
+} scsi_system_preset_t;
+
+typedef enum
+{
+    DEV_PRESET_NONE = 0,
+    DEV_PRESET_ST32430N
+} scsi_device_preset_t;
+
+
+// This struct should only have new settings added to the end
+// as it maybe saved and restored directly from flash memory
+typedef struct __attribute__((__packed__)) scsi_system_settings_t
+{
+    // Settings for host compatibility 
+    uint8_t quirks;
+    uint8_t selectionDelay;
+    uint8_t maxSyncSpeed;
+    uint8_t phyMode;
+    uint16_t initPreDelay;
+    uint16_t initPostDelay;
+
+    bool enableUnitAttention;
+    bool enableSCSI2;
+    bool enableSelLatch;
+    bool mapLunsToIDs;
+    bool enableParity;
+    bool useFATAllocSize;
+} scsi_system_settings_t;
+
+// This struct should only have new setting added to the end
+// as it maybe saved and restored directly from flash memory
+typedef struct __attribute__((__packed__)) scsi_device_settings_t
+{
+    // Settings that can be set on all or specific device
+    int prefetchBytes;
+    uint16_t sectorsPerTrack;
+    uint16_t headsPerCylinder;
+
+    char prodId[16];
+    char serial[16];
+    char vendor[8];
+    char revision[4];
+
+    uint16_t vol;
+    uint8_t deviceType;
+    uint8_t deviceTypeModifier;
+    uint8_t ejectButton;
+    bool nameFromImage;
+    bool rightAlignStrings;
+    bool reinsertOnInquiry;
+    bool reinsertAfterEject;
+    bool disableMacSanityCheck;
+} scsi_device_settings_t;
+
+
+class ZuluSCSISettings
+{
+public:
+    // Initialize settings for all devices with a preset configuration,
+    //  or return the default config if unknown system type.
+    // Then overwrite any settings with those in the CONFIGFILE
+    scsi_system_settings_t *initSystem(const char *presetName);
+
+    // Copy any shared device setting done the initSystemSettings as default settings, 
+    // or return the default config if unknown device type.
+    // Then overwrite any settings with those in the CONFIGFILE
+    scsi_device_settings_t *initDevicePName(uint8_t scsiId, const char *presetName);
+    scsi_device_settings_t *initDevicePreset(uint8_t scsiId, const scsi_device_preset_t preset);
+    // return the system settings struct to read values
+    scsi_system_settings_t *getSystem();
+
+    // return the device settings struct to read values
+    scsi_device_settings_t *getDevice(uint8_t scsiId);
+
+    // return the system preset enum
+    scsi_system_preset_t getSystemPreset();
+
+    // return the system preset name
+    const char* getSystemPresetName();
+
+    // return the device preset enum
+    scsi_device_preset_t getDevicePreset(uint8_t scsiId);
+
+    // return the device preset name
+    const char* getDevicePresetName(uint8_t scsiId);
+
+protected:
+    // Set default drive vendor / product info after the image file
+    // is loaded and the device type is known.
+    void setDefaultDriveInfo(uint8_t scsiId, const char *presetName);
+
+    // Settings for the specific device
+    const char **deviceInitST32430N(uint8_t scsiId);
+
+    // Informative name of the preset configuration, or NULL for defaults
+    // The last presetName is for the System preset name. The rest are for
+    // corresponding SCSI Ids.
+    scsi_system_preset_t m_sysPreset;
+    scsi_device_preset_t m_devPreset[8];
+
+    // These are setting for host compatibility
+    scsi_system_settings_t m_sys;
+
+    // The last dev will be copied over the other dev scsi Id for device defaults.
+    // It is set during when the system settings are initialized
+    scsi_device_settings_t m_dev[9];
+} ;
+
+extern ZuluSCSISettings g_scsi_settings;
+#endif // __cplusplus

+ 6 - 2
zuluscsi.ini

@@ -3,7 +3,7 @@
 # Settings that apply to all SCSI IDs
 
 # Select a system preset to apply default settings
-# Known systems: "Mac", "MacPlus"
+# Known systems: "Mac", "MacPlus", "MPC3000"
 #System="Mac"
 
 #Debug = 0   # Same effect as DIPSW2, enables verbose log messages
@@ -36,6 +36,10 @@
 #InitiatorImageHandling = 0 # 0: skip exisitng images, 1: create new image with incrementing suffix, 2: overwrite exising image
 
 # Settings that can be specified either per-device or for all devices.
+
+# Select a device preset to apply default settings
+# Known systems: "ST32430N"
+#Device = "ST32430N"
 #Vendor = "QUANTUM"
 #Product = "FIREBALL1"
 #Version = "1.0"
@@ -44,7 +48,7 @@
 #TypeModifier = 0  # Affects only INQUIRY response
 #SectorsPerTrack = 63
 #HeadsPerCylinder = 255
-#RightAlignStrings = 0 # Right-align SCSI vendor / product strings, defaults on if Quirks = 1
+#RightAlignStrings = 0 # Right-align SCSI vendor / product strings
 #PrefetchBytes = 8192 # Maximum number of bytes to prefetch after a read request, 0 to disable
 #ReinsertCDOnInquiry = 1 # Reinsert any ejected CD-ROM image on Inquiry command
 #ReinsertAfterEject = 1 # Reinsert next CD image after eject, if multiple images configured.