Internal_Datalogger but with USB support removed (for MAX40108 Demo board), proof of concept that MAX32625 can be used successfully with VDDB(USB) left unpowered, as long as the USB library is not used.

Dependencies:   max32625pico CmdLine

Revision:
10:04022a61b527
Parent:
9:45f98573eb6d
Child:
11:2b8adc78618a
--- a/DataLogger_Internal.cpp	Fri Dec 18 09:29:35 2020 +0000
+++ b/DataLogger_Internal.cpp	Fri Jan 15 03:11:15 2021 +0000
@@ -1610,23 +1610,24 @@
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
 // MAX11410 individual channels 1=LSB, 2=Volt, 0=Disabled
 typedef enum SPI_AIN_Enable_t {
-    Disable = 0,
-    Enable_LSB = 1,
-    Enable_Volt = 2,
+    SPI_AIN_Disable = 0,
+    SPI_AIN_Enable_LSB = 1,
+    SPI_AIN_Enable_Volt = 2,
 } SPI_AIN_Enable_t;
 uint8_t SPI_AIN_Enable_ch[NUM_DUT_ANALOG_IN_CHANNELS] = {
-    Enable_LSB,  // AIN0 1=LSB
-    Enable_LSB,  // AIN1 1=LSB
-    Enable_LSB,  // AIN2 1=LSB
-    Enable_LSB,  // AIN3 1=LSB
-    Enable_LSB,  // AIN4 1=LSB
-    Enable_LSB,  // AIN5 1=LSB
-    Enable_LSB,  // AIN6 1=LSB
-    Enable_LSB,  // AIN7 1=LSB
-    Enable_LSB,  // AIN8 1=LSB
-    Enable_LSB,  // AIN9 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN0 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN1 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN2 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN3 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN4 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN5 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN6 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN7 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN8 1=LSB
+    SPI_AIN_Enable_LSB,  // AIN9 1=LSB
 };
 //
+double SPI_AIN_Voltage[NUM_DUT_ANALOG_IN_CHANNELS];
 #endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
 //  ---------- Measure_Voltage_custom_props in Measure_Voltage @pre and in class properties ----------
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
@@ -1785,12 +1786,12 @@
 //#endif
 const int NUM_PLATFORM_ANALOG_IN_CHANNELS = 6;
 const double adc_full_scale_voltage[NUM_PLATFORM_ANALOG_IN_CHANNELS] = {
-    1.2,
-    1.2,
-    1.2,
-    1.2,
-    1.2,
-    1.2
+    analogInPin_fullScaleVoltage[0], // 1.2,
+    analogInPin_fullScaleVoltage[1], // 1.2,
+    analogInPin_fullScaleVoltage[2], // 1.2,
+    analogInPin_fullScaleVoltage[3], // 1.2,
+    analogInPin_fullScaleVoltage[4], // 6.0
+    analogInPin_fullScaleVoltage[5], // 6.0
 };
 // Platform ADC individual channels 1=LSB, 2=Volt, 0=Disabled
 typedef enum Platform_AIN_Enable_t {
@@ -1825,6 +1826,54 @@
 #endif
 #endif // defined(LOG_PLATFORM_AIN)
 
+//--------------------------------------------------
+// Option to use Command forwarding to Auxiliary serial port
+// Command forwarding to Auxiliary serial port TX/RX
+// Command forwarding to AUX serial TX/RX cmdLine_AUXserial
+// Command forwarding to DAPLINK serial TX/RX cmdLine_DAPLINKserial
+// prefer cmdLine_AUXserial if available, else cmdLine_DAPLINKserial; else we don't have this feature
+#ifndef USE_AUX_SERIAL_CMD_FORWARDING
+#define USE_AUX_SERIAL_CMD_FORWARDING 1
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+#if USE_AUX_SERIAL_CMD_FORWARDING
+// Command forwarding to Auxiliary serial port TX/RX #257 -- global parameters
+const size_t RX_STRING_BUF_SIZE = 1000;
+int g_auxSerialCom_baud = 9600; //!< baud rate Auxiliary serial port
+// transmit command string by AUX TX
+#if 0
+int g_auxSerialCom_tx_wait_echo = 0;       //!< TX wait for each character echo?
+int g_auxSerialCom_tx_char_delay_ms = 0;   //!< TX delay after each char?
+int g_auxSerialCom_tx_line_delay_ms = 0;   //!< TX delay after each CR/LF?
+#endif
+//  capture received string from AUX RX
+Timer g_auxSerialCom_Timer;
+int g_auxSerialCom_Timer_begin_message_ms = 0; //!< start of message
+int g_auxSerialCom_Timer_begin_rx_idle_ms = 0; //!< recent RX character timestamp
+int g_auxSerialCom_message_ms = 10000;     //!< maximum RX message total response time
+int g_auxSerialCom_rx_idle_ms = 500;     //!< maximum RX message idle time between characters
+int g_auxSerialCom_rx_max_count = RX_STRING_BUF_SIZE-1;   //!< maximum RX message total length
+const int aux_serial_cmd_forwarding_rx_eot_not_used = 'x';
+int g_auxSerialCom_rx_eot = aux_serial_cmd_forwarding_rx_eot_not_used;         //!< capture RX until match end of text char
+//~ int g_auxSerialCom_rx_eot = 0;     //!< capture RX until match end of text string?
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+#if USE_AUX_SERIAL_CMD_FORWARDING
+    // TODO WIP Command forwarding to Auxiliary serial port TX/RX #257
+    // prefer cmdLine_AUXserial if available, else cmdLine_DAPLINKserial; else we don't have this feature
+# if HAS_AUX_SERIAL
+    // TODO WIP Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257
+# elif HAS_DAPLINK_SERIAL
+    // TODO WIP Command forwarding to DAPLINK serial TX/RX cmdLine_DAPLINKserial #257
+# else // neither HAS_AUX_SERIAL HAS_DAPLINK_SERIAL
+#warning "USE_AUX_SERIAL_CMD_FORWARDING should not be enabled without HAS_AUX_SERIAL or HAS_DAPLINK_SERIAL"
+# endif // HAS_AUX_SERIAL HAS_DAPLINK_SERIAL
+# if HAS_AUX_SERIAL
+    // TODO WIP Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257
+# endif // HAS_AUX_SERIAL
+# if HAS_DAPLINK_SERIAL
+    // TODO WIP Command forwarding to DAPLINK serial TX/RX cmdLine_DAPLINKserial #257
+# endif // HAS_DAPLINK_SERIAL
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+
 // CODE GENERATOR: example code for ADC: serial port declaration
 //--------------------------------------------------
 // Declare the Serial driver
@@ -1951,7 +2000,15 @@
 # if HAS_AUX_SERIAL
 // TX/RX auxiliary UART port cmdLine_AUXserial AUXserial
 CmdLine cmdLine_AUXserial(AUXserial, "AUXserial");
-uint8_t Datalogger_enable_AUXserial = true;
+uint8_t Datalogger_enable_AUXserial = {
+#if USE_AUX_SERIAL_CMD_FORWARDING
+    // Command forwarding to Auxiliary serial port;
+    // don't accept commands from Auxiliary serial port
+    false
+#else // USE_AUX_SERIAL_CMD_FORWARDING
+    true
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+};
 # endif // HAS_AUX_SERIAL
 # if HAS_DAPLINK_SERIAL
 CmdLine cmdLine_DAPLINKserial(DAPLINKserial, "DAPLINK");
@@ -2017,7 +2074,11 @@
 {
     // ? -- help
     //~ cmdLine.serial().printf("\r\nMenu:");
+    //
     cmdLine.serial().printf("\r\n # -- lines beginning with # are comments");
+#if defined(SPI_ADC_DeviceName) // SPI connected ADC
+    cmdLine.serial().printf("\r\n ! -- Init");
+#endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
 #if USE_SELFTEST
     cmdLine.serial().printf("\r\n . -- SelfTest");
 #endif // USE_SELFTEST
@@ -2025,7 +2086,43 @@
 // CODE GENERATOR: help menu if has_register_write_command: *regname? -- read register; *regname=regvalue -- write register
     cmdLine.serial().printf("\r\n * -- read core registers\r\n *regname? -- read register\r\n *regname=regvalue -- write register");
     // cmdLine.serial().printf("\r\n 01 23 45 67 89 ab cd ef -- write and read raw hex codes");
-#endif // USE_STAR_REG_READWRITE        
+#endif // USE_STAR_REG_READWRITE
+//
+#if USE_AUX_SERIAL_CMD_FORWARDING
+    // Command forwarding to Auxiliary serial port TX/RX #257 -- main_menu_help
+    //~ cmdLine.serial().printf("\r\n > -- auxiliary UART port");
+    // prefer cmdLine_AUXserial if available, else cmdLine_DAPLINKserial; else we don't have this feature
+# if HAS_AUX_SERIAL
+    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257
+    if (cmdLine_AUXserial.nameStr())
+    {
+        cmdLine.serial().printf("\r\n > -- auxiliary UART port [%s]", cmdLine_AUXserial.nameStr());
+    }
+# elif HAS_DAPLINK_SERIAL
+    // Command forwarding to DAPLINK serial TX/RX cmdLine_DAPLINKserial #257
+    if (cmdLine_DAPLINKserial.nameStr())
+    {
+        cmdLine.serial().printf("\r\n > -- auxiliary UART port [%s]", cmdLine_DAPLINKserial.nameStr());
+    }
+# endif // HAS_AUX_SERIAL HAS_DAPLINK_SERIAL
+# if HAS_AUX_SERIAL || HAS_DAPLINK_SERIAL
+    // WIP Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257
+    cmdLine.serial().printf("\r\n >xyzzy -- Forward command/data 'xyzzy' to aux TX/RX");
+    cmdLine.serial().printf("\r\n >>xyzzy -- Forward 'xyzzy' to aux TX/RX, no key=value parsing");
+    cmdLine.serial().printf("\r\n >>>xyzzy -- Forward '>xyzzy' to aux TX/RX, no key=value parsing");
+    cmdLine.serial().printf("\r\n >baud=%d -- configure aux TX/RX port", g_auxSerialCom_baud);
+#if 0
+    cmdLine.serial().printf("\r\n >tx_wait_echo=%d -- configure TX wait for each character echo", g_auxSerialCom_tx_wait_echo);
+    cmdLine.serial().printf("\r\n >tx_char_delay_ms=%d -- configure TX delay after each char", g_auxSerialCom_tx_char_delay_ms);
+    cmdLine.serial().printf("\r\n >tx_line_delay_ms=%d -- configure TX delay after each CR/LF", g_auxSerialCom_tx_line_delay_ms);
+#endif
+    cmdLine.serial().printf("\r\n >message_ms=%d -- maximum RX message total response time", g_auxSerialCom_message_ms);
+    cmdLine.serial().printf("\r\n >rx_idle_ms=%d -- maximum RX message idle time between characters", g_auxSerialCom_rx_idle_ms);
+    cmdLine.serial().printf("\r\n >rx_max_count=%d -- maximum RX message total length", g_auxSerialCom_rx_max_count);
+    cmdLine.serial().printf("\r\n >rx_eot=%d -- capture RX until match end of text char (unless %d)", g_auxSerialCom_rx_eot, aux_serial_cmd_forwarding_rx_eot_not_used);
+# endif // HAS_AUX_SERIAL
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+//
 #if USE_DATALOGGER_TRIGGER // support Datalog trigger
     // TODO Datalog trigger menu
     // set Datalogger_Trigger to trigger_Halt or trigger_FreeRun
@@ -2274,6 +2371,33 @@
             diagnostic_led_EOF();
             break;
 #endif
+#if defined(SPI_ADC_DeviceName) // SPI connected ADC
+        case '!':     // device init
+            {
+                cmdLine.serial().printf("Init");
+                // call function Init
+                uint8_t result = g_MAX11410_device.Init();
+                // cmdLine.serial().printf(" =%d\r\n", result);
+                cmdLine.serial().printf(" =%d\r\n", result);
+#if USE_CUSTOM_REG_INIT // custom_reg_init_addr[], custom_reg_init_data[], custom_reg_init_count
+                // in command '!' device init, apply list of custom register writes after init
+                // custom_reg_init_addr[], custom_reg_init_data[], custom_reg_init_count
+                for (unsigned int index = 0; index < custom_reg_init_count; index++) {
+                    uint8_t regAddress = custom_reg_init_addr[index];
+                    uint32_t regData = custom_reg_init_data[index];
+                    cmdLine.serial().printf("*%s=0x%06.6x",
+                        g_MAX11410_device.RegName((MAX11410::MAX11410_CMD_enum_t)regAddress),
+                        regData
+                    );
+                    g_MAX11410_device.RegWrite((MAX11410::MAX11410_CMD_enum_t)regAddress, regData);
+                }
+#endif // USE_CUSTOM_REG_INIT
+                g_MAX11410_device.v_filter = SPI_AIN_Cfg_v_filter_ch[0];
+                g_MAX11410_device.v_ctrl = SPI_AIN_Cfg_v_ctrl_ch[0];
+                g_MAX11410_device.v_pga = SPI_AIN_Cfg_v_pga_ch[0];
+            }
+            break;
+#endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
 #if USE_SELFTEST
         case '.':
         {
@@ -2291,7 +2415,172 @@
         break;         // case '%'
 #endif // APPLICATION_ArduinoPinsMonitor
 #if USE_STAR_REG_READWRITE // * command read/write reg *reg? *reg=value
+        // reuse the Serial_Tester command *regName=regValue
+// CODE GENERATOR: generate * command read/write reg *reg? *reg=value
+        case '*':
+        {
+            // if buffer starts with a regName:
+            // for each reg value (0..n) if(cmdLine.has_keyword(device.regName(r))):
+            // cmdLine.serial().printf(" scan RegName...\r\n");
+        }
+        break;
 #endif // USE_STAR_REG_READWRITE // * command read/write reg *reg? *reg=value
+//
+#if 1 // USE_AUX_SERIAL_CMD_FORWARDING && (HAS_AUX_SERIAL || HAS_DAPLINK_SERIAL)
+        // TODO WIP Command forwarding to Auxiliary serial port TX/RX #257 -- main_menu_onEOLcommandParser
+        case '>':
+        {
+            // prefer cmdLine_AUXserial if available, else cmdLine_DAPLINKserial; else we don't have this feature
+# if HAS_AUX_SERIAL
+            // TODO WIP Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257
+            CmdLine& cmdLine_AuxSerial = cmdLine_AUXserial;
+            Serial& AuxSerial = AUXserial;
+# elif HAS_DAPLINK_SERIAL
+            // TODO WIP Command forwarding to DAPLINK serial TX/RX cmdLine_DAPLINKserial #257
+            CmdLine& cmdLine_AuxSerial = cmdLine_DAPLINKserial;
+            Serial& AuxSerial = DAPLINKserial;
+# else // neither HAS_AUX_SERIAL HAS_DAPLINK_SERIAL
+#warning "USE_AUX_SERIAL_CMD_FORWARDING should not be enabled without HAS_AUX_SERIAL or HAS_DAPLINK_SERIAL"
+# endif // HAS_AUX_SERIAL HAS_DAPLINK_SERIAL
+            //
+            // >> suppress key=value parsing
+            bool suppress_parsing = (cmdLine[1] == '>');
+            if (suppress_parsing == false) {
+                // int g_auxSerialCom_baud = 9600; //!< baud rate Auxiliary serial port
+                if (cmdLine.parse_int_dec("baud", g_auxSerialCom_baud))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- baud rate
+                    cmdLine_AuxSerial.serial().printf("\r\n*** New Baud Rate %d ***\r\n", g_auxSerialCom_baud);
+                    AuxSerial.baud(g_auxSerialCom_baud);
+                    cmdLine_AuxSerial.serial().printf("\r\n*** Baud Rate was set to %d ***\r\n", g_auxSerialCom_baud);
+                }
+#if 0
+                // int g_auxSerialCom_tx_wait_echo = 0;       //!< TX wait for each character echo?
+                if (cmdLine.parse_int_dec("tx_wait_echo", g_auxSerialCom_tx_wait_echo))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- tx_wait_echo
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** tx_wait_echo was set to %d ***\r\n", g_auxSerialCom_tx_wait_echo);
+                    cmdLine.serial().printf("\r\n  tx_wait_echo=%d", g_auxSerialCom_tx_wait_echo);
+                }
+                // int g_auxSerialCom_tx_char_delay_ms = 0;   //!< TX delay after each char?
+                if (cmdLine.parse_int_dec("tx_char_delay_ms", g_auxSerialCom_tx_char_delay_ms))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- tx_char_delay_ms
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** tx_char_delay_ms was set to %d ***\r\n", g_auxSerialCom_tx_char_delay_ms);
+                    cmdLine.serial().printf("\r\n  tx_char_delay_ms=%dms", g_auxSerialCom_tx_char_delay_ms);
+                }
+                // int g_auxSerialCom_tx_line_delay_ms = 0;   //!< TX delay after each CR/LF?
+                if (cmdLine.parse_int_dec("tx_line_delay_ms", g_auxSerialCom_tx_line_delay_ms))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- tx_line_delay_ms
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** tx_line_delay_ms was set to %d ***\r\n", g_auxSerialCom_tx_line_delay_ms);
+                    cmdLine.serial().printf("\r\n  tx_line_delay_ms=%dms", g_auxSerialCom_tx_line_delay_ms);
+                }
+#endif
+                // int g_auxSerialCom_message_ms = 0;     //!< capture RX until response timeout?
+                if (cmdLine.parse_int_dec("message_ms", g_auxSerialCom_message_ms))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- message_ms
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** message_ms was set to %d ***\r\n", g_auxSerialCom_message_ms);
+                    cmdLine.serial().printf("\r\n  message_ms timeout %dms", g_auxSerialCom_message_ms);
+                }
+                // int g_auxSerialCom_rx_idle_ms = 0;     //!< capture RX until idle timeout?
+                if (cmdLine.parse_int_dec("rx_idle_ms", g_auxSerialCom_rx_idle_ms))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- rx_idle_ms
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** rx_idle_ms was set to %d ***\r\n", g_auxSerialCom_rx_idle_ms);
+                    cmdLine.serial().printf("\r\n  rx_idle_ms timeout %dms", g_auxSerialCom_rx_idle_ms);
+                }
+                // int g_auxSerialCom_rx_max_count = 0;   //!< capture RX until max character count?
+                if (cmdLine.parse_int_dec("rx_max_count", g_auxSerialCom_rx_max_count))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- rx_max_count
+                    //~ cmdLine_AuxSerial.serial().printf("\r\n*** rx_max_count was set to %d ***\r\n", g_auxSerialCom_rx_max_count);
+                    cmdLine.serial().printf("\r\n  rx_max_count %d bytes", g_auxSerialCom_rx_max_count);
+                }
+                // int g_auxSerialCom_rx_eot = 0;         //!< capture RX until match end of text char?
+                if (cmdLine.parse_int_dec("rx_eot", g_auxSerialCom_rx_eot))
+                {
+                    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- rx_eot
+                    //~ cmdLine_AUXserial.serial().printf("\r\n*** rx_eot was set to %d ***\r\n", g_auxSerialCom_rx_eot);
+                    cmdLine.serial().printf("\r\n  rx_eot %d", g_auxSerialCom_rx_eot);
+                }
+            }
+            // Command forwarding to AUX serial TX/RX cmdLine_AuxSerial #257 -- send outgoing_string
+            char* outgoing_string = (char*)cmdLine.str();
+            // > use key=value parsing
+            // >> suppress key=value parsing
+            if (suppress_parsing) {
+                cmdLine.serial().printf("\r\n  suppress_parsing outgoing_string=\"%s\"", outgoing_string);
+                outgoing_string++; // skip the first '>'
+                outgoing_string++; // skip the second '>'
+            } else {
+                // TODO: after parsing, key=value pairs should be deleted, but outgoing_string=">xyzzy abc=def"
+                cmdLine.serial().printf("\r\n  after parsing, outgoing_string=\"%s\"", outgoing_string);
+                outgoing_string++; // skip the first '>'
+            }
+            static char rx_string_buf[RX_STRING_BUF_SIZE];
+            unsigned int rx_string_length = 0;
+            cmdLine.serial().printf("\r\n  >%s\r\n  <", outgoing_string);
+            rx_string_buf[0] = '\0';
+            rx_string_length = 0;
+            //
+            // int g_auxSerialCom_tx_wait_echo = 0;       //!< TX wait for each character echo?
+            // int g_auxSerialCom_tx_char_delay_ms = 0;   //!< TX delay after each char?
+            // int g_auxSerialCom_tx_line_delay_ms = 0;   //!< TX delay after each CR/LF?
+            //
+            // int g_auxSerialCom_Timer_begin_message_ms = 0; //!< start of message
+            // int g_auxSerialCom_Timer_begin_rx_idle_ms = 0; //!< recent RX character timestamp
+            // int g_auxSerialCom_message_ms = 10000;     //!< maximum RX message total response time
+            // int g_auxSerialCom_rx_idle_ms = 2000;     //!< maximum RX message idle time between characters
+            // int g_auxSerialCom_rx_max_count = RX_STRING_BUF_SIZE-1;   //!< maximum RX message total length
+            // int g_auxSerialCom_rx_eot = '\r';         //!< capture RX until match end of text char
+            //~ cmdLine_AuxSerial.serial().printf("\r\n*** TODO forward %s ***\r\n", outgoing_string);
+            //
+            // TODO: send whole string or send character-by-character?
+            cmdLine_AuxSerial.serial().printf("%s", outgoing_string);
+            cmdLine_AuxSerial.serial().printf("\r\n");
+            g_auxSerialCom_Timer.start();
+            g_auxSerialCom_Timer_begin_message_ms = g_auxSerialCom_Timer.read_ms(); // start of message
+            g_auxSerialCom_Timer_begin_rx_idle_ms = g_auxSerialCom_Timer.read_ms(); // recent RX character timestamp
+            while (rx_string_length < (RX_STRING_BUF_SIZE-1)) {
+                if ((g_auxSerialCom_Timer.read_ms() - g_auxSerialCom_Timer_begin_message_ms) > g_auxSerialCom_message_ms) {
+                    cmdLine.serial().printf("\r\n  message_ms timeout %dms", g_auxSerialCom_message_ms);
+                    break;
+                }
+                if ((g_auxSerialCom_Timer.read_ms() - g_auxSerialCom_Timer_begin_rx_idle_ms) > g_auxSerialCom_rx_idle_ms) {
+                    cmdLine.serial().printf("\r\n  rx_idle_ms timeout %dms", g_auxSerialCom_rx_idle_ms);
+                    break;
+                }
+                if (rx_string_length >= g_auxSerialCom_rx_max_count) {
+                    cmdLine.serial().printf("\r\n  rx_max_count %d bytes", g_auxSerialCom_rx_max_count);
+                    break;
+                }
+                if (AuxSerial.readable()) {
+                    g_auxSerialCom_Timer_begin_rx_idle_ms = g_auxSerialCom_Timer.read_ms(); // recent RX character timestamp
+                    char ch = AuxSerial.getc();
+                    rx_string_buf[rx_string_length++] = ch;
+                    rx_string_buf[rx_string_length] = '\0'; // null terminate buffer
+                    cmdLine.serial().printf("%s", &(rx_string_buf[rx_string_length-1]) ); // immediate character echo
+                    if (g_auxSerialCom_rx_eot != aux_serial_cmd_forwarding_rx_eot_not_used) {
+                        if (ch == g_auxSerialCom_rx_eot) {
+                            cmdLine.serial().printf("\r\n  rx_eot %d", g_auxSerialCom_rx_eot);
+                            break;
+                        }
+                    }
+                }
+            } // end while (rx_string_length < (RX_STRING_BUF_SIZE-1))
+            #if 1
+            // print summary. is this needed? we already print aux rx as it is received.
+            rx_string_buf[rx_string_length] = '\0'; // null terminate buffer
+            cmdLine.serial().printf("\r\n  >%s", outgoing_string);
+            cmdLine.serial().printf("\r\n  <%s\r\n", rx_string_buf);
+            #endif
+            //
+        }
+        break;         // case '>'
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
+//
 #if USE_DATALOGGER_TRIGGER // support Datalog trigger
         // TODO Datalog trigger menu
         // set Datalogger_Trigger to trigger_Halt or trigger_FreeRun
@@ -2427,6 +2716,7 @@
                                 }
                             } // end if cmdLine[2] channel_index
                         } // end for channel_index
+                        // Datalogger_PrintHeader(cmdLine);
                         if (Datalogger_enable_serial) {
                             Datalogger_PrintHeader(cmdLine);
                         }
@@ -2524,14 +2814,15 @@
     // column header banner for csv data columns
         int field_index = 0;
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
-        for (int channel_index = 0; channel_index < NUM_DUT_ANALOG_IN_CHANNELS; field_index++, channel_index++) {
-            if (SPI_AIN_Enable_ch[channel_index] == Disable) {
+        for (int channel_index = 0; channel_index < NUM_DUT_ANALOG_IN_CHANNELS; channel_index++) {
+            if (SPI_AIN_Enable_ch[channel_index] == SPI_AIN_Disable) {
                 continue;
             }
             // comma between fields
             if (field_index > 0) {
                 cmdLine.serial().printf(",");
             }
+            field_index++;
             // AIN_index column header prefix
 #if SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
             // MAX11410 v_ctrl bipolar configuration or unipolar?
@@ -2544,17 +2835,14 @@
 #else // SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
             cmdLine.serial().printf("\"AIN%d", channel_index);
 #endif // SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
-            if (SPI_AIN_Enable_ch[channel_index] == Enable_LSB) {
-                cmdLine_DAPLINKserial.serial().printf("\"AIN%d", channel_index);
-# endif // HAS_DAPLINK_SERIAL
-#if LOG_PLATFORM_ANALOG_IN_LSB
+            if (SPI_AIN_Enable_ch[channel_index] == SPI_AIN_Enable_LSB) {
                 // _LSB column header suffix
                 cmdLine.serial().printf("_LSB\"");
 # if HAS_DAPLINK_SERIAL
                 cmdLine_DAPLINKserial.serial().printf("_LSB\"");
 # endif // HAS_DAPLINK_SERIAL
             }
-            else if (SPI_AIN_Enable_ch[channel_index] == Enable_Volt) {
+            else if (SPI_AIN_Enable_ch[channel_index] == SPI_AIN_Enable_Volt) {
                 // _V column header suffix
                 cmdLine.serial().printf("_V\"");
 # if HAS_DAPLINK_SERIAL
@@ -2611,15 +2899,68 @@
             // @param[in] g_MAX11410_device.channelNumber_0_15: AIN Channel Number
             // @param[in] g_MAX11410_device.PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
             // @param[in] g_MAX11410_device.chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
-            int channelId_0_9 = NUM_DUT_ANALOG_IN_CHANNELS-1+1;
+            //~ int channelId_0_9 = NUM_DUT_ANALOG_IN_CHANNELS-1+1;
             //g_MAX11410_device.channelNumber_0_15 = channelId_0_9;
             //g_MAX11410_device.PowerManagement_0_2 = 0;
             //g_MAX11410_device.chan_id_0_1 = 1;
             //----------------------------------------
             // scan AIN0..AIN9
             //
+#if 1
+            g_MAX11410_device.v_filter = SPI_AIN_Cfg_v_filter_ch[0];
+            g_MAX11410_device.v_ctrl = SPI_AIN_Cfg_v_ctrl_ch[0];
+            g_MAX11410_device.v_pga = SPI_AIN_Cfg_v_pga_ch[0];
+            //
+            // diagnostic GPIO pulse on MAX11410 GP1 pin (0xc3 = logic 0, 0xc4 = logic 1)
+            g_MAX11410_device.RegWrite(MAX11410::CMD_r000_0101_dddd_xddd_GP1_CTRL, 0xc3); // GP1 = 0
+            //
+            int field_index = 0;
+            for (int channel_index = 0; channel_index < NUM_DUT_ANALOG_IN_CHANNELS; channel_index++) {
+                if (SPI_AIN_Enable_ch[channel_index] == SPI_AIN_Disable) {
+                    continue;
+                }
+                field_index++;
+                g_MAX11410_device.v_filter = SPI_AIN_Cfg_v_filter_ch[channel_index];
+                g_MAX11410_device.v_ctrl = SPI_AIN_Cfg_v_ctrl_ch[channel_index];
+                g_MAX11410_device.v_pga = SPI_AIN_Cfg_v_pga_ch[channel_index];
+                //
+                // WIP SampleRate_of_FILTER_CONV_START() MAX11410EMC-FW slow ODR 10Sps #262
+                // adjust the MAX11410.loop_limit value if the sample rate is set to a value slower than 20sps
+                // SampleRate_of_FILTER_CONV_START(uint8_t FILTER_RegValue, uint8_t CONV_START_RegValue)
+                double SampleRate = g_MAX11410_device.SampleRate_of_FILTER_CONV_START(g_MAX11410_device.v_filter, MAX11410::MAX11410_CONV_TYPE_enum_t::CONV_TYPE_01_Continuous);
+                if (SampleRate < 20.0) {
+                    g_MAX11410_device.loop_limit = 32767; // TODO: is this timeout long enough for the slow output data rates?
+                }
+                //
+                // diagnostic GPIO pulse on MAX11410 GP0 pin (0xc3 = logic 0, 0xc4 = logic 1)
+                g_MAX11410_device.RegWrite(MAX11410::CMD_r000_0100_dddd_xddd_GP0_CTRL, 0xc3); // GP0 = 0
+                //
+#if SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
+                // MAX11410 v_ctrl bipolar configuration or unipolar?
+                if ((SPI_AIN_Cfg_v_ctrl_ch[channel_index] & 0x40) == 0) {
+                    const MAX11410::MAX11410_AINP_SEL_enum_t ainp = (MAX11410::MAX11410_AINP_SEL_enum_t)(channel_index);
+                    const MAX11410::MAX11410_AINN_SEL_enum_t ainn = (MAX11410::MAX11410_AINN_SEL_enum_t)(channel_index^1);
+                    SPI_AIN_Voltage[channel_index] = g_MAX11410_device.Measure_Voltage(ainp, ainn);
+                    // @post AINcode[ainp]: measurement result LSB code
+                }
+                else {
+                    const MAX11410::MAX11410_AINP_SEL_enum_t ainp = (MAX11410::MAX11410_AINP_SEL_enum_t)(channel_index);
+                    const MAX11410::MAX11410_AINN_SEL_enum_t ainn = MAX11410::AINN_SEL_1010_GND;
+                    SPI_AIN_Voltage[channel_index] = g_MAX11410_device.Measure_Voltage(ainp, ainn);
+                    // @post AINcode[ainp]: measurement result LSB code
+                }
+#endif // SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
+                //
+                // diagnostic GPIO pulse on MAX11410 GP0 pin (0xc3 = logic 0, 0xc4 = logic 1)
+                g_MAX11410_device.RegWrite(MAX11410::CMD_r000_0100_dddd_xddd_GP0_CTRL, 0xc4); // GP0 = 1
+                //
+            }
+            // diagnostic GPIO pulse on MAX11410 GP1 pin (0xc3 = logic 0, 0xc4 = logic 1)
+            g_MAX11410_device.RegWrite(MAX11410::CMD_r000_0101_dddd_xddd_GP1_CTRL, 0xc4); // GP1 = 1
+#else
             g_MAX11410_device.Read_All_Voltages();
-#endif // SPI_ADC_DeviceName == MAX11410 // SPI connected ADC
+#endif
+#endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
 #if defined(LOG_PLATFORM_AIN) // Datalog Arduino platform analog inputs
             // mbed
             // Platform board uses simple analog inputs
@@ -2630,7 +2971,8 @@
             Platform_LSB[3] = analogIn3.read();
             Platform_LSB[4] = analogIn4.read();
             Platform_LSB[5] = analogIn5.read();
-#elif LOG_PLATFORM_ANALOG_IN_VOLTS
+#endif
+#if LOG_PLATFORM_ANALOG_IN_VOLTS
             Platform_Voltage[0] = analogIn0.read() * adc_full_scale_voltage[0];
             Platform_Voltage[1] = analogIn1.read() * adc_full_scale_voltage[1];
             Platform_Voltage[2] = analogIn2.read() * adc_full_scale_voltage[2];
@@ -2653,15 +2995,24 @@
 {
             int field_index = 0;
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
-            for (int channel_index = 0; channel_index < NUM_DUT_ANALOG_IN_CHANNELS; field_index++, channel_index++) {
-                if (SPI_AIN_Enable_ch[channel_index] == Disable) {
+            for (int channel_index = 0; channel_index < NUM_DUT_ANALOG_IN_CHANNELS; channel_index++) {
+                if (SPI_AIN_Enable_ch[channel_index] == SPI_AIN_Disable) {
                     continue;
                 }
                 // comma between fields
                 if (field_index > 0) {
                     cmdLine.serial().printf(",");
                 }
-                cmdLine.serial().printf("%d", g_MAX11410_device.AINcode[channel_index]);
+                field_index++;
+                if (SPI_AIN_Enable_ch[channel_index] == Platform_AIN_Enable_LSB) {
+                    cmdLine.serial().printf("%d", g_MAX11410_device.AINcode[channel_index]);
+                }
+                if (SPI_AIN_Enable_ch[channel_index] == Platform_AIN_Enable_Volt) {
+                    // TODO: report Voltage instead of LSB
+                    // Serial.print(SPI_AIN_Voltage[channel_index]);
+                    static char strOutLineBuffer[16];
+                    cmdLine.serial().printf("%6.6f", SPI_AIN_Voltage[channel_index]);
+                }
             }
 #if VERIFY_PART_ID_IN_LOOP
             // PART_ID field: Device ID Validation
@@ -2749,6 +3100,16 @@
     //~ cmdLine.on_immediate_0x7b = on_immediate_0x7b;
     //~ cmdLine.on_immediate_0x7d = on_immediate_0x7d;
 # if HAS_DAPLINK_SERIAL
+#if 0 // HARD CRASH -- USE_AUX_SERIAL_CMD_FORWARDING
+    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- init aux baud rate g_auxSerialCom_baud
+    // TODO: if g_auxSerialCom_baud is other than the default 9600 baud,
+    // then the auxiliary serial port baud rate should be updated.
+# if HAS_AUX_SERIAL
+# else
+    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- init aux baud rate g_auxSerialCom_baud
+    DAPLINKserial.baud(g_auxSerialCom_baud);
+# endif
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
     cmdLine_DAPLINKserial.clear();
     //~ cmdLine_DAPLINKserial.serial().printf("\r\n cmdLine_DAPLINKserial.serial().printf test\r\n");
     cmdLine_DAPLINKserial.onEOLcommandParser = main_menu_onEOLcommandParser;
@@ -2758,6 +3119,12 @@
 # endif
 # if HAS_AUX_SERIAL
     // TX/RX auxiliary UART port cmdLine_AUXserial AUXserial
+#if 0 // HARD CRASH -- USE_AUX_SERIAL_CMD_FORWARDING
+    // Command forwarding to AUX serial TX/RX cmdLine_AUXserial #257 -- init aux baud rate g_auxSerialCom_baud
+    // TODO: if g_auxSerialCom_baud is other than the default 9600 baud,
+    // then the auxiliary serial port baud rate should be updated.
+    AUXserial.baud(g_auxSerialCom_baud);
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
     cmdLine_AUXserial.clear();
     //~ cmdLine_AUXserial.serial().printf("\r\n cmdLine_AUXserial.serial().printf test\r\n");
     cmdLine_AUXserial.onEOLcommandParser = main_menu_onEOLcommandParser;
@@ -2780,7 +3147,7 @@
     cmdLine_AUXserial.serial().printf("\r\nInternal_DataLogger\r\n"); // instead of Hello_MAX11410
 # endif // HAS_AUX_SERIAL
 #endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
-    
+
     // CODE GENERATOR: get spi properties from device
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
     if (g_SPI_SCLK_Hz > g_MAX11410_device.get_spi_frequency())
@@ -2830,12 +3197,17 @@
 
         // column header banner for csv data columns
         Datalogger_Need_PrintHeader = true;
-                
+
         while(1) { // this code repeats forever
         // this code repeats forever
 
 #if USE_CMDLINE_MENUS // support CmdLine command menus
             // TODO support CmdLine command menus (like on Serial_Tester); help and usual boilerplate
+#if USE_AUX_SERIAL_CMD_FORWARDING
+            // Command forwarding to Auxiliary serial port;
+            // don't accept commands from Auxiliary serial port
+#else // USE_AUX_SERIAL_CMD_FORWARDING
+            // Accept commands from Auxiliary serial port
 # if HAS_AUX_SERIAL
             if (AUXserial.readable()) {
                 cmdLine_AUXserial.append(AUXserial.getc());
@@ -2846,6 +3218,7 @@
                 cmdLine_DAPLINKserial.append(DAPLINKserial.getc());
             }
 # endif // HAS_DAPLINK_SERIAL
+#endif // USE_AUX_SERIAL_CMD_FORWARDING
             if (serial.readable()) {
                 int c = serial.getc(); // instead of getc() or fgetc()
                 cmdLine.append(c);