Selaa lähdekoodia

Add ability to reset via terminal for RP2 boards

Pressing `m` or `r` then `y` will reboot the board. If `m` is pressed
the board will reboot into mass storage.

This will be useful to users playing with their timings or modifying
their `zuluscsi.ini` settings.

For users modifying their timings, they will need to reboot into mass
storage, edit their `zulu_timings.ini` file, then do an 'r' reboot to
reclock their board with their new settings.

Most zuluscsi.ini file settings get reloaded after ejecting the
mass storage device.
J. Morio Sakaguchi 1 vuosi sitten
vanhempi
sitoutus
4a3aa6931f

+ 2 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h

@@ -108,6 +108,8 @@ uint32_t platform_sys_clock_in_hz();
 // Attempt to reclock the MCU - unsupported
 inline zuluscsi_reclock_status_t platform_reclock(uint32_t clk_in_khz){return ZULUSCSI_RECLOCK_NOT_SUPPORTED;}
 
+// Returns true if reboot was for mass storage - unsupported
+inline bool platform_rebooted_into_mass_storage() {return false;}
 
 // Reinitialize SD card connection and save log from interrupt context.
 // This can be used in crash handlers.

+ 2 - 0
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.h

@@ -99,6 +99,8 @@ uint32_t platform_sys_clock_in_hz();
 // Attempt to reclock the MCU - unsupported
 inline zuluscsi_reclock_status_t platform_reclock(uint32_t clk_in_khz){return ZULUSCSI_RECLOCK_NOT_SUPPORTED;}
 
+// Returns true if reboot was for mass storage - unsupported
+inline bool platform_rebooted_into_mass_storage() {return false;}
 
 // Reinitialize SD card connection and save log from interrupt context.
 // This can be used in crash handlers.

+ 79 - 19
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.cpp

@@ -1,20 +1,20 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * 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. 
- * 
+ * (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. 
- * 
+ * 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/>.
 **/
@@ -48,7 +48,7 @@
 #ifdef ZULUSCSI_NETWORK
 extern "C" {
 #  include <pico/cyw43_arch.h>
-} 
+}
 #endif // ZULUSCSI_NETWORK
 
 #ifdef ENABLE_AUDIO_OUTPUT
@@ -153,6 +153,17 @@ zuluscsi_reclock_status_t platform_reclock(uint32_t clock_in_khz)
     return ZULUSCSI_RECLOCK_FAILED;
 }
 
+bool platform_rebooted_into_mass_storage()
+{
+    volatile uint32_t* scratch0 = (uint32_t *)(WATCHDOG_BASE + WATCHDOG_SCRATCH0_OFFSET);
+    if (*scratch0 == REBOOT_INTO_MASS_STORAGE_MAGIC_NUM)
+    {
+        *scratch0 = 0;
+        return true;
+    }
+    return false;
+}
+
 #ifdef HAS_DIP_SWITCHES
 enum pin_setup_state_t  {SETUP_FALSE, SETUP_TRUE, SETUP_UNDETERMINED};
 static pin_setup_state_t read_setup_ack_pin()
@@ -160,7 +171,7 @@ static pin_setup_state_t read_setup_ack_pin()
     /* Revision 2022d of the RP2040 hardware has problems reading initiator DIP switch setting.
      * The 74LVT245 hold current is keeping the GPIO_ACK state too strongly.
      * Detect this condition by toggling the pin up and down and seeing if it sticks.
-     * 
+     *
      * Revision 2023b and 2023c of the Pico boards have issues reading TERM and DEBUG DIP switch
      * settings. GPIO_ACK is externally pulled down to ground for later revisions.
      * If the state is detected as undetermined then the board is the 2023b or 2023c revision.
@@ -172,7 +183,7 @@ static pin_setup_state_t read_setup_ack_pin()
     gpio_conf(SCSI_IN_ACK,  GPIO_FUNC_SIO, false, true,  false, true,  false);
     delay(1);
     bool ack_state1 = gpio_get(SCSI_IN_ACK);
-    
+
     // Strong output low, then pullup
     //        pin             function       pup   pdown   out    state  fast
     gpio_conf(SCSI_IN_ACK,  GPIO_FUNC_SIO, false, false, true,  false, false);
@@ -203,7 +214,7 @@ void platform_init()
 
     pio_clear_instruction_memory(pio0);
     pio_clear_instruction_memory(pio1);
-    
+
     /* First configure the pins that affect external buffer directions.
      * RP2040 defaults to pulldowns, while these pins have external pull-ups.
      */
@@ -225,13 +236,13 @@ void platform_init()
 # if defined(ZULUSCSI_PICO) || defined(ZULUSCSI_PICO_2)
     // Initiator dip setting works on all rev 2023b, 2023c, and newer rev Pico boards
     g_scsi_initiator = !gpio_get(DIP_INITIATOR);
-    
-    working_dip = SETUP_UNDETERMINED != read_setup_ack_pin();    
+
+    working_dip = SETUP_UNDETERMINED != read_setup_ack_pin();
     if (working_dip)
     {
         dbglog = !gpio_get(DIP_DBGLOG);
         termination = !gpio_get(DIP_TERM);
-        
+
     }
 # else
     g_scsi_initiator = SETUP_TRUE == read_setup_ack_pin();
@@ -254,7 +265,7 @@ void platform_init()
 
 #ifdef HAS_DIP_SWITCHES
     if (working_dip)
-    {       
+    {
         logmsg("DIP switch settings: debug log ", (int)dbglog, ", termination ", (int)termination);
         g_log_debug = dbglog;
 
@@ -440,7 +451,7 @@ bool platform_is_initiator_mode_enabled()
 }
 
 void platform_disable_led(void)
-{   
+{
     //        pin      function       pup   pdown  out    state fast
     gpio_conf(LED_PIN, GPIO_FUNC_SIO, false,false, false, false, false);
     logmsg("Disabling status LED");
@@ -479,6 +490,7 @@ void platform_emergency_log_save()
 
 
 static void usb_log_poll();
+static void usb_input_poll();
 
 __attribute__((noinline))
 void show_hardfault(uint32_t *sp)
@@ -568,17 +580,64 @@ static void usb_log_poll()
         uint32_t len = available;
         if (len == 0) return;
         if (len > CFG_TUD_CDC_EP_BUFSIZE) len = CFG_TUD_CDC_EP_BUFSIZE;
-        
+
         // Update log position by the actual number of bytes sent
         // If USB CDC buffer is full, this may be 0
         uint32_t actual = 0;
         actual = Serial.write(data, len);
         logpos -= available - actual;
     }
+
 #endif // PIO_FRAMEWORK_ARDUINO_NO_USB
 }
 
+// Grab input from USB Serial terminal
+static void usb_input_poll()
+{
+    #ifndef PIO_FRAMEWORK_ARDUINO_NO_USB
+    // Caputure reboot key sequence
+    static bool mass_storage_reboot_keyed = false;
+    static bool basic_reboot_keyed = false;
+    volatile uint32_t* scratch0 = (uint32_t *)(WATCHDOG_BASE + WATCHDOG_SCRATCH0_OFFSET);
+    int32_t available = Serial.available();
+    if(available > 0)
+    {
+        int32_t read = Serial.read();
+        switch((char) read)
+        {
+            case 'R':
+            case 'r':
+                basic_reboot_keyed = true;
+                mass_storage_reboot_keyed = false;
+                logmsg("Basic reboot requested, press 'y' to engage or any key to clear");
+                break;
+            case 'M':
+            case 'm':
+                mass_storage_reboot_keyed = true;
+                basic_reboot_keyed = false;
+                logmsg("Boot into mass storage requested, press 'y' to engage or any key to clear");
+                *scratch0 = REBOOT_INTO_MASS_STORAGE_MAGIC_NUM;
+                break;
+            case 'Y':
+            case 'y':
+                if (basic_reboot_keyed || mass_storage_reboot_keyed)
+                {
+                    logmsg("Rebooting", mass_storage_reboot_keyed ? " into mass storage": "");
+                    watchdog_reboot(0, 0, 2000);
+                }
+                break;
+            case '\n':
+                break;
 
+            default:
+                if (basic_reboot_keyed || mass_storage_reboot_keyed)
+                    logmsg("Cleared reboot setting");
+                mass_storage_reboot_keyed = false;
+                basic_reboot_keyed = false;
+        }
+    }
+#endif // PIO_FRAMEWORK_ARDUINO_NO_USB
+}
 // Use ADC to implement supply voltage monitoring for the +3.0V rail.
 // This works by sampling the temperature sensor channel, which has
 // a voltage of 0.7 V, allowing to calculate the VDD voltage.
@@ -758,9 +817,10 @@ void platform_reset_watchdog()
 // Can be left empty or used for platform-specific processing.
 void platform_poll()
 {
+    usb_input_poll();
     usb_log_poll();
     adc_poll();
-    
+
 #ifdef ENABLE_AUDIO_OUTPUT
     audio_poll();
 #endif // ENABLE_AUDIO_OUTPUT

+ 11 - 8
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.h

@@ -1,20 +1,20 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * 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. 
- * 
+ * (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. 
- * 
+ * 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/>.
 **/
@@ -116,6 +116,9 @@ uint32_t platform_sys_clock_in_hz();
 // Attempt to reclock the MCU
 zuluscsi_reclock_status_t platform_reclock(uint32_t clk_in_khz);
 
+// Returns true if reboot was for mass storage
+bool platform_rebooted_into_mass_storage();
+
 // Set callback that will be called during data transfer to/from SD card.
 // This can be used to implement simultaneous transfer to SCSI bus.
 typedef void (*sd_callback_t)(uint32_t bytes_complete);

+ 54 - 53
src/ZuluSCSI.cpp

@@ -1,47 +1,47 @@
-/*  
+/*
  *  ZuluSCSI™
  *  Copyright (c) 2022-2024 Rabbit Hole Computing™
- * 
+ *
  * This project is based on BlueSCSI:
  *
  *  BlueSCSI
  *  Copyright (c) 2021  Eric Helgeson, Androda
- *  
+ *
  * This work incorporates work by following
  *  Copyright (c) 2023 joshua stein <jcs@jcs.org>
  *  Copyright (c) 2023 zigzagjoe
- * 
- *  This file is free software: you may copy, redistribute and/or modify it  
- *  under the terms of the GNU General Public License as published by the  
- *  Free Software Foundation, either version 2 of the License, or (at your  
- *  option) any later version.  
- *  
- *  This file 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://github.com/erichelgeson/bluescsi.  
- *  
- * This file incorporates work covered by the following copyright and  
- * permission notice:  
- *  
- *     Copyright (c) 2019 komatsu   
- *  
- *     Permission to use, copy, modify, and/or distribute this software  
- *     for any purpose with or without fee is hereby granted, provided  
- *     that the above copyright notice and this permission notice appear  
- *     in all copies.  
- *  
- *     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL  
- *     WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED  
- *     WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE  
- *     AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR  
- *     CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS  
- *     OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,  
- *     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN  
- *     CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  
+ *
+ *  This file is free software: you may copy, redistribute and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This file 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://github.com/erichelgeson/bluescsi.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ *     Copyright (c) 2019 komatsu
+ *
+ *     Permission to use, copy, modify, and/or distribute this software
+ *     for any purpose with or without fee is hereby granted, provided
+ *     that the above copyright notice and this permission notice appear
+ *     in all copies.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ *     WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ *     WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ *     AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ *     CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ *     OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ *     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ *     CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include <SdFat.h>
@@ -129,7 +129,7 @@ void save_logfile(bool always = false)
     {
       g_logfile.write(log_get_buffer(&prev_log_pos));
       g_logfile.flush();
-      
+
       prev_log_len = loglen;
       prev_log_save = millis();
     }
@@ -166,13 +166,13 @@ void print_sd_info()
   uint64_t size = (uint64_t)SD.vol()->clusterCount() * SD.vol()->bytesPerCluster();
   logmsg("SD card detected, FAT", (int)SD.vol()->fatType(),
           " volume size: ", (int)(size / 1024 / 1024), " MB");
-  
+
   cid_t sd_cid;
 
   if(SD.card()->readCID(&sd_cid))
   {
     logmsg("SD MID: ", (uint8_t)sd_cid.mid, ", OID: ", (uint8_t)sd_cid.oid[0], " ", (uint8_t)sd_cid.oid[1]);
-    
+
     char sdname[6] = {sd_cid.pnm[0], sd_cid.pnm[1], sd_cid.pnm[2], sd_cid.pnm[3], sd_cid.pnm[4], 0};
     logmsg("SD Name: ", sdname);
     logmsg("SD Date: ", (int)sd_cid.mdtMonth(), "/", sd_cid.mdtYear());
@@ -571,7 +571,7 @@ bool findHDDImages()
   for (int i = 0; i < NUM_SCSIID; i++)
   {
     const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
-    
+
     if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
     {
       int capacity_kB = ((uint64_t)cfg->scsiSectors * cfg->bytesPerSector) / 1024;
@@ -610,7 +610,7 @@ bool findHDDImages()
           }
         }
     }
-  } 
+  }
 
   if (removable_count == 1)
   {
@@ -620,7 +620,7 @@ bool findHDDImages()
     else if (eject_btn_set == 0)
     {
       logmsg("Found 1 removable device, to set an eject button see EjectButton in the '", CONFIGFILE,"', or the http://zuluscsi.com/manual");
-    } 
+    }
   }
   else if (removable_count > 1)
   {
@@ -750,19 +750,19 @@ static void reinitSCSI()
 
     logmsg("Direct/Raw mode enabled, using hardware switches for configuration");
     logmsg("-- SCSI ID set via DIP switch to ", (int) g_hw_config.scsi_id());
-    char raw_filename[32];  
-    uint32_t start =  g_scsi_settings.getDevice(scsiId)->sectorSDBegin; 
+    char raw_filename[32];
+    uint32_t start =  g_scsi_settings.getDevice(scsiId)->sectorSDBegin;
     uint32_t end = g_scsi_settings.getDevice(scsiId)->sectorSDEnd;
 
     if (start == end && end == 0)
     {
       strcpy(raw_filename, "RAW:0:0xFFFFFFFF");
-    } 
+    }
     else
     {
       snprintf(raw_filename, sizeof(raw_filename), "RAW:0x%X:0x%X", start, end);
     }
-    
+
     success = scsiDiskOpenHDDImage(scsiId, raw_filename, 0,
                                    g_hw_config.blocksize(), g_hw_config.device_type());
     if (success)
@@ -778,7 +778,7 @@ static void reinitSCSI()
   }
   else
 #endif // ZULUSCSI_HARDWARE_CONFIG
-  { 
+  {
     readSCSIDeviceConfig();
     findHDDImages();
 
@@ -814,7 +814,7 @@ static void reinitSCSI()
     platform_network_wifi_join(scsiDev.boardCfg.wifiSSID, scsiDev.boardCfg.wifiPassword);
   }
 #endif // ZULUSCSI_NETWORK
-  
+
 }
 // Place all the setup code that requires the SD card to be initialized here
 // Which is pretty much everything after platform_init and and platform_late_init
@@ -879,7 +879,7 @@ static void zuluscsi_setup_sd_card()
     }
 
     print_sd_info();
-    
+
     char presetName[32];
     ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
     scsi_system_settings_t *cfg = g_scsi_settings.initSystem(presetName);
@@ -891,8 +891,8 @@ static void zuluscsi_setup_sd_card()
     }
     platform_post_sd_card_init();
     reinitSCSI();
-    
-    
+
+
     boot_delay_ms = cfg->initPostDelay;
     if (boot_delay_ms > 0)
     {
@@ -923,10 +923,11 @@ extern "C" void zuluscsi_setup(void)
 
 #ifdef PLATFORM_MASS_STORAGE
   static bool check_mass_storage = true;
-  if (check_mass_storage && g_scsi_settings.getSystem()->enableUSBMassStorage)
+  if (check_mass_storage && g_scsi_settings.getSystem()->enableUSBMassStorage
+      || platform_rebooted_into_mass_storage())
   {
     check_mass_storage = false;
-    
+
     // perform checks to see if a computer is attached and return true if we should enter MSC mode.
     if (platform_sense_msc())
     {
@@ -1001,7 +1002,7 @@ extern "C" void zuluscsi_main_loop(void)
   if (!g_sdcard_present)
   {
     // Try to remount SD card
-    do 
+    do
     {
       g_sdcard_present = mountSDCard();
 

+ 11 - 8
src/ZuluSCSI_config.h

@@ -1,21 +1,21 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
  * Portions copyright (c) 2023 joshua stein <jcs@jcs.org>
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * 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. 
- * 
+ * (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. 
- * 
+ * 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/>.
 **/
@@ -125,6 +125,9 @@
 #define ZIP100_DISK_SIZE    100663296 // bytes
 #define ZIP250_DISK_SIZE    250640384 // bytes
 
+// Settings for rebooting
+#define REBOOT_INTO_MASS_STORAGE_MAGIC_NUM 0x5eeded
+
 // Reclocking return status
 typedef enum
 {