Parcourir la source

RP2040: Add logging to USB

Implemented using the ArduinoCore-mbed USBCDC send_nb() non-blocking
function to avoid disturbing timing of SCSI tasks.
Petteri Aimonen il y a 2 ans
Parent
commit
bb916389be

+ 42 - 0
lib/ZuluSCSI_platform_BS2/ZuluSCSI_platform.cpp

@@ -10,6 +10,7 @@
 #include <hardware/structs/xip_ctrl.h>
 #include <platform/mbed_error.h>
 #include <multicore.h>
+#include <USB/PluggableUSBSerial.h>
 
 extern "C" {
 
@@ -237,6 +238,38 @@ void mbed_error_hook(const mbed_error_ctx * error_context)
 /* Debug logging and watchdog            */
 /*****************************************/
 
+// Send log data to USB UART if USB is connected.
+// Data is retrieved from the shared log ring buffer and
+// this function sends as much as fits in USB CDC buffer.
+//
+// This is normally called by platform_reset_watchdog() in
+// the normal polling loop. If code hangs, the watchdog_callback()
+// also starts calling this after 2 seconds.
+// This ensures that log messages get passed even if code hangs,
+// but does not unnecessarily delay normal execution.
+static void usb_log_poll()
+{
+    static uint32_t logpos = 0;
+
+    if (_SerialUSB.ready())
+    {
+        // Retrieve pointer to log start and determine number of bytes available.
+        uint32_t newlogpos = logpos;
+        const char *data = log_get_buffer(&newlogpos);
+
+        // Limit to CDC packet size
+        uint32_t len = (newlogpos - logpos);
+        if (len == 0) return;
+        if (len > CDC_MAX_PACKET_SIZE) len = CDC_MAX_PACKET_SIZE;
+
+        // Update log position by the actual number of bytes sent
+        // If USB CDC buffer is full, this may be 0
+        uint32_t actual = 0;
+        _SerialUSB.send_nb((uint8_t*)data, len, &actual);
+        logpos += actual;
+    }
+}
+
 // This function is called for every log message.
 void platform_log(const char *s)
 {
@@ -253,6 +286,12 @@ static void watchdog_callback(unsigned alarm_num)
 {
     g_watchdog_timeout -= 1000;
 
+    if (g_watchdog_timeout < WATCHDOG_CRASH_TIMEOUT - 1000)
+    {
+        // Been stuck for at least a second, start dumping USB log
+        usb_log_poll();
+    }
+
     if (g_watchdog_timeout <= WATCHDOG_CRASH_TIMEOUT - WATCHDOG_BUS_RESET_TIMEOUT)
     {
         if (!scsiDev.resetFlag)
@@ -290,6 +329,7 @@ static void watchdog_callback(unsigned alarm_num)
                 p += 4;
             }
 
+            usb_log_poll();
             platform_emergency_log_save();
 
             platform_boot_to_main_firmware();
@@ -312,6 +352,8 @@ void platform_reset_watchdog()
         hardware_alarm_set_target(3, delayed_by_ms(get_absolute_time(), 1000));
         g_watchdog_initialized = true;
     }
+
+    usb_log_poll();
 }
 
 /*****************************************/

+ 42 - 0
lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.cpp

@@ -10,6 +10,7 @@
 #include <hardware/structs/xip_ctrl.h>
 #include <platform/mbed_error.h>
 #include <multicore.h>
+#include <USB/PluggableUSBSerial.h>
 
 extern "C" {
 
@@ -317,6 +318,38 @@ void mbed_error_hook(const mbed_error_ctx * error_context)
 /* Debug logging and watchdog            */
 /*****************************************/
 
+// Send log data to USB UART if USB is connected.
+// Data is retrieved from the shared log ring buffer and
+// this function sends as much as fits in USB CDC buffer.
+//
+// This is normally called by platform_reset_watchdog() in
+// the normal polling loop. If code hangs, the watchdog_callback()
+// also starts calling this after 2 seconds.
+// This ensures that log messages get passed even if code hangs,
+// but does not unnecessarily delay normal execution.
+static void usb_log_poll()
+{
+    static uint32_t logpos = 0;
+
+    if (_SerialUSB.ready())
+    {
+        // Retrieve pointer to log start and determine number of bytes available.
+        uint32_t newlogpos = logpos;
+        const char *data = log_get_buffer(&newlogpos);
+
+        // Limit to CDC packet size
+        uint32_t len = (newlogpos - logpos);
+        if (len == 0) return;
+        if (len > CDC_MAX_PACKET_SIZE) len = CDC_MAX_PACKET_SIZE;
+
+        // Update log position by the actual number of bytes sent
+        // If USB CDC buffer is full, this may be 0
+        uint32_t actual = 0;
+        _SerialUSB.send_nb((uint8_t*)data, len, &actual);
+        logpos += actual;
+    }
+}
+
 // This function is called for every log message.
 void platform_log(const char *s)
 {
@@ -333,6 +366,12 @@ static void watchdog_callback(unsigned alarm_num)
 {
     g_watchdog_timeout -= 1000;
 
+    if (g_watchdog_timeout < WATCHDOG_CRASH_TIMEOUT - 1000)
+    {
+        // Been stuck for at least a second, start dumping USB log
+        usb_log_poll();
+    }
+
     if (g_watchdog_timeout <= WATCHDOG_CRASH_TIMEOUT - WATCHDOG_BUS_RESET_TIMEOUT)
     {
         if (!scsiDev.resetFlag || !g_scsiHostPhyReset)
@@ -371,6 +410,7 @@ static void watchdog_callback(unsigned alarm_num)
                 p += 4;
             }
 
+            usb_log_poll();
             platform_emergency_log_save();
 
             platform_boot_to_main_firmware();
@@ -393,6 +433,8 @@ void platform_reset_watchdog()
         hardware_alarm_set_target(3, delayed_by_ms(get_absolute_time(), 1000));
         g_watchdog_initialized = true;
     }
+
+    usb_log_poll();
 }
 
 /*****************************************/