Test program running on MAX32625MBED. Control through USB Serial commands using a terminal emulator such as teraterm or putty.

Dependencies:   MaximTinyTester CmdLine MAX541 MAX5715 USBDevice

Revision:
10:228a52f8107d
Parent:
9:9b4232e20020
Child:
11:9fa2402071de
--- a/main.cpp	Fri Jun 21 11:25:28 2019 +0000
+++ b/main.cpp	Wed Jun 26 01:05:04 2019 +0000
@@ -3833,566 +3833,523 @@
 }
 
 //--------------------------------------------------
-// main menu command-line parser
-// invoked by CmdLine::append(char ch) or CmdLine::idleAppendIfReadable()
-void main_menu_onEOLcommandParser(CmdLine & cmdLine)
+// diagnostic commands submenu
+// invoked by main_menu_onEOLcommandParser case '%'
+void pinsMonitor_submenu_onEOLcommandParser(CmdLine & cmdLine)
 {
-    // DIAGNOSTIC: print line buffer
-    //~ cmdLine.serial().printf("\r\nmain_menu_onEOLcommandParser: ~%s~\r\n", cmdLine.str());
+    // % diagnostic commands submenu
+    // %Hpin -- digital output high
+    // %Lpin -- digital output low
+    // %?pin -- digital input
+    // %A %Apin -- analog input
+    // %Ppin df=xx -- pwm output
+    // %Wpin -- measure high pulsewidth input in usec
+    // %wpin -- measure low pulsewidth input in usec
+    // %I... -- I2C diagnostics
+    // %IP -- I2C probe
+    // %IC scl=100khz ADDR=? -- I2C configure
+    // %IW byte byte ... byte RD=? ADDR=0x -- write
+    // %IR ADDR=? RD=? -- read
+    // %I^ cmd=? -- i2c_smbus_read_word_data
+    // %S... -- SPI diagnostics
+    // %SC sclk=1Mhz -- SPI configure
+    // %SW -- write (write and read)
+    // %SR -- read (alias for %SW because SPI always write and read)
+    // A-Z,a-z,0-9 reserved for application use
+    //
+    // get pinIndex from cmdLine[2]
+    //int pinIndex = cmdLine[2];
+    // *** warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
+    //int pinIndex = strtoul((char *)((void *)(cmdLine.str()) + 2), NULL, 10); // strtol(str, NULL, 10): get decimal value
+    //                                                        ^
+    char strPinIndex[3];
+    strPinIndex[0] = cmdLine[2];
+    strPinIndex[1] = cmdLine[3];
+    strPinIndex[2] = '\0';
+    int pinIndex = strtoul(strPinIndex, NULL, 10);         // strtol(str, NULL, 10): get decimal value
+    //cmdLine.serial().printf(" pinIndex=%d ", pinIndex);
     //
-    switch (cmdLine[0])
+    // get next character
+    switch (cmdLine[1])
     {
+#if HAS_digitalInOuts
+        case 'H': case 'h':
+        {
+            // %Hpin -- digital output high
+#if ARDUINO_STYLE
+            pinMode(pinIndex, OUTPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+            digitalWrite(pinIndex, HIGH);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+#else
+            DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
+            digitalInOutPin.output();
+            digitalInOutPin.write(1);
+#endif
+            cmdLine.serial().printf(" digitalInOutPin %d Output High ", pinIndex);
+        }
+        break;
+        case 'L': case 'l':
+        {
+            // %Lpin -- digital output low
+#if ARDUINO_STYLE
+            pinMode(pinIndex, OUTPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+            digitalWrite(pinIndex, LOW);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+#else
+            DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
+            digitalInOutPin.output();
+            digitalInOutPin.write(0);
+#endif
+            cmdLine.serial().printf(" digitalInOutPin %d Output Low ", pinIndex);
+        }
+        break;
         case '?':
-            main_menu_status(cmdLine);
-            main_menu_help(cmdLine);
-            // print command prompt
-            //cmdLine.serial().printf("\r\n>");
-            break;
-        case '\r': case '\n':     // ignore blank line
-        case '\0':     // ignore empty line
-        case '#':     // ignore comment line
-            // # -- lines beginning with # are comments
-            main_menu_status(cmdLine);
-            //~ main_menu_help(cmdLine);
-            // print command prompt
-            //cmdLine.serial().printf("\r\n>");
-            break;
-#if ECHO_EOF_ON_EOL
-        case '\x04':     // Unicode (U+0004) EOT END OF TRANSMISSION = CTRL+D as EOF end of file
-            cmdLine.serial().printf("\x04");     // immediately echo EOF for test scripting
-            diagnostic_led_EOF();
-            break;
-        case '\x1a':     // Unicode (U+001A) SUB SUBSTITUTE = CTRL+Z as EOF end of file
-            cmdLine.serial().printf("\x1a");     // immediately echo EOF for test scripting
-            diagnostic_led_EOF();
-            break;
-#endif
-#if APPLICATION_ArduinoPinsMonitor
-        case '.':
         {
-            // . -- SelfTest
-            cmdLine.serial().printf("SelfTest()");
-            SelfTest(cmdLine);
+            // %?pin -- digital input
+#if ARDUINO_STYLE
+            pinMode(pinIndex, INPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+#else
+            DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
+            digitalInOutPin.input();
+#endif
+            serial.printf(" digitalInOutPin %d Input ", pinIndex);
+#if ARDUINO_STYLE
+            int value = digitalRead(pinIndex);
+#else
+            int value = digitalInOutPin.read();
+#endif
+            cmdLine.serial().printf("%d ", value);
         }
         break;
-        case '%':
+#endif
+        //
+#if HAS_analogIns
+        case 'A': case 'a':
         {
-            // TODO: consolidate "Arduino Pins Monitor" under '%' submenu -- APPLICATION_ArduinoPinsMonitor
-            // % standardize diagnostic commands
-            // %Hpin -- digital output high
-            // %Lpin -- digital output low
-            // %?pin -- digital input
             // %A %Apin -- analog input
-            // %Ppin df=xx -- pwm output
-            // %Wpin -- measure high pulsewidth input in usec
-            // %wpin -- measure low pulsewidth input in usec
+#if analogIn4_IS_HIGH_RANGE_OF_analogIn0
+            // Platform board uses AIN4,AIN5,.. as high range of AIN0,AIN1,..
+            for (int pinIndex = 0; pinIndex < 2; pinIndex++)
+            {
+                int cPinIndex = '0' + pinIndex;
+                AnalogIn& analogInPin = find_analogInPin(cPinIndex);
+                float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
+                float normValue_0_1 = analogInPin.read();
+                //
+                int pinIndexH = pinIndex + 4;
+                int cPinIndexH = '0' + pinIndexH;
+                AnalogIn& analogInPinH = find_analogInPin(cPinIndexH);
+                float adc_full_scale_voltageH = analogInPin_fullScaleVoltage[pinIndexH];
+                float normValueH_0_1 = analogInPinH.read();
+                //
+                cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV  AIN%c = %7.3f%% = %1.3fV  \r\n",
+                                        cPinIndex,
+                                        normValue_0_1 * 100.0,
+                                        normValue_0_1 * adc_full_scale_voltage,
+                                        cPinIndexH,
+                                        normValueH_0_1 * 100.0,
+                                        normValueH_0_1 * adc_full_scale_voltageH
+                                        );
+            }
+            for (int pinIndex = 2; pinIndex < 4; pinIndex++)
+            {
+                int cPinIndex = '0' + pinIndex;
+                AnalogIn& analogInPin = find_analogInPin(cPinIndex);
+                float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
+                float normValue_0_1 = analogInPin.read();
+                //
+                cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV\r\n",
+                                        cPinIndex,
+                                        normValue_0_1 * 100.0,
+                                        normValue_0_1 * adc_full_scale_voltage
+                                        );
+            }
+#else // analogIn4_IS_HIGH_RANGE_OF_analogIn0
+            // Platform board uses simple analog inputs
+            // assume standard Arduino analog inputs A0-A5
+            for (int pinIndex = 0; pinIndex < 6; pinIndex++)
+            {
+                int cPinIndex = '0' + pinIndex;
+                AnalogIn& analogInPin = find_analogInPin(cPinIndex);
+                float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
+                float normValue_0_1 = analogInPin.read();
+                //
+                cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV\r\n",
+                                        cPinIndex,
+                                        normValue_0_1 * 100.0,
+                                        normValue_0_1 * adc_full_scale_voltage
+                                        );
+            }
+#endif // analogIn4_IS_HIGH_RANGE_OF_analogIn0
+        }
+        break;
+#endif
+        //
+#if HAS_SPI2_MAX541
+        case 'D': case 'd':
+        {
+            // %D -- DAC output MAX541 (SPI2) -- need cmdLine.parse_float(voltageV)
+            // MAX541 max541(spi2_max541, spi2_max541_cs);
+            float voltageV = max541.Get_Voltage();
+            // if (cmdLine[2] == '+') {
+            //     // %D+
+            //     voltageV = voltageV * 1.25f;
+            //     if (voltageV >= max541.VRef) voltageV = max541.VRef;
+            //     SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
+            // }
+            // else if (cmdLine[2] == '-') {
+            //     // %D-
+            //     voltageV = voltageV * 0.75f;
+            //     if (voltageV < 0.1f) voltageV = 0.1f;
+            //     SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
+            // }
+            if (cmdLine.parse_float("V", voltageV))
+            {
+                // %D V=1.234 -- set voltage
+                max541.Set_Voltage(voltageV);
+            }
+            else if (cmdLine.parse_float("TEST", voltageV))
+            {
+                // %D TEST=1.234 -- set voltage and compare with AIN0
+                SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
+            }
+            else if (cmdLine.parse_float("CAL", voltageV))
+            {
+                // %D CAL=1.234 -- calibrate VRef and compare with AIN0
+
+                max541.Set_Code(0x8000); // we don't know the fullscale voltage yet, so set code to midscale
+                double max541_midscale_V = analogInPin_fullScaleVoltage[4] * analogIn4.read(); // TARGET_MAX32630 J1.5 AIN_4 = AIN0 / 5.0     fullscale is 6.0V
+                const int average_count = 100;
+                const double average_K = 0.25;
+                for (int count = 0; count < average_count; count++) {
+                    double measurement_V = analogInPin_fullScaleVoltage[4] * analogIn4.read(); // TARGET_MAX32630 J1.5 AIN_4 = AIN0 / 5.0     fullscale is 6.0V
+                    max541_midscale_V = ((1 - average_K) * max541_midscale_V) + (average_K * measurement_V);
+                }
+                max541.VRef = 2.0 * max541_midscale_V;
+                cmdLine.serial().printf(
+                    "\r\n      MAX541 midscale = %1.3fV, so fullscale = %1.3fV",
+                    max541_midscale_V, max541.VRef);
+                // Detect whether MAX541 is really connected to MAX32625MBED.AIN0/AIN4
+                voltageV = 1.0f;
+                SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
+            }
+            else {
+                // %D -- print MAX541 DAC status
+                cmdLine.serial().printf("MAX541 code=0x%4.4x = %1.3fV  VRef=%1.3fV\r\n",
+                                        max541.Get_Code(), max541.Get_Voltage(), max541.VRef);
+            }
+        }
+        break;
+#endif
+
+        //
+#if HAS_I2C // SUPPORT_I2C
+        case 'I': case 'i':
             // %I... -- I2C diagnostics
             // %IP -- I2C probe
             // %IC scl=100khz ADDR=? -- I2C configure
             // %IW byte byte ... byte RD=? ADDR=0x -- write
             // %IR ADDR=? RD=? -- read
             // %I^ cmd=? -- i2c_smbus_read_word_data
+            // get next character
+            // TODO: parse cmdLine arg (ADDR=\d+)? --> g_I2C_deviceAddress7
+            cmdLine.parse_byte_hex("ADDR", g_I2C_deviceAddress7);
+            // TODO: parse cmdLine arg (RD=\d)? --> g_I2C_read_count
+            g_I2C_read_count = 0;         // read count must be reset every command
+            cmdLine.parse_byte_dec("RD", g_I2C_read_count);
+            // TODO: parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress
+            cmdLine.parse_byte_hex("CMD", g_I2C_command_regAddress);
+            switch (cmdLine[2])
+            {
+                case 'P': case 'p':
+                {
+                    // %IP -- I2C probe
+                    HuntAttachedI2CDevices(cmdLine, 0x03, 0x77);
+                }
+                break;
+                case 'C': case 'c':
+                {
+                    bool isUpdatedI2CConfig = false;
+                    // %IC scl=100khz ADDR=? -- I2C configure
+                    // parse cmdLine arg (SCL=\d+(kHZ|MHZ)?)? --> g_I2C_SCL_Hz
+                    if (cmdLine.parse_frequency_Hz("SCL", g_I2C_SCL_Hz))
+                    {
+                        isUpdatedI2CConfig = true;
+                        // TODO1: validate g_I2C_SCL_Hz against system clock frequency F_CPU
+                        if (g_I2C_SCL_Hz > limit_max_I2C_SCL_Hz)
+                        {
+                            g_I2C_SCL_Hz = limit_max_I2C_SCL_Hz;
+                        }
+                        if (g_I2C_SCL_Hz < limit_min_I2C_SCL_Hz)
+                        {
+                            g_I2C_SCL_Hz = limit_min_I2C_SCL_Hz;
+                        }
+                    }
+                    if (isUpdatedI2CConfig)
+                    {
+                        // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
+                        I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
+                        i2cMaster.frequency(g_I2C_SCL_Hz);
+                        i2cMaster.start();
+                        i2cMaster.stop();
+                        i2cMaster.frequency(g_I2C_SCL_Hz);
+                        cmdLine.serial().printf(
+                            "\r\n %%IC ADDR=0x%2.2x=(0x%2.2x>>1) SCL=%d=%1.3fkHz -- I2C config",
+                            g_I2C_deviceAddress7, (g_I2C_deviceAddress7 << 1), g_I2C_SCL_Hz,
+                            (g_I2C_SCL_Hz / 1000.));
+                        i2cMaster.start();
+                        i2cMaster.stop();
+                    }
+                }
+                break;
+                case 'W': case 'w':
+                {
+                    // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
+                    I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
+                    i2cMaster.frequency(g_I2C_SCL_Hz);
+                    // %IW byte byte ... byte RD=? ADDR=0x -- write
+                    // parse cmdLine byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT];
+                    #define MAX_I2C_BYTE_COUNT 32
+                    size_t byteCount = byteCount;
+                    static char mosiData[MAX_I2C_BYTE_COUNT];
+                    static char misoData[MAX_I2C_BYTE_COUNT];
+                    if (cmdLine.parse_byteCount_byteList_hex(byteCount, mosiData,
+                                                             MAX_I2C_BYTE_COUNT))
+                    {
+                        // hex dump mosiData[0..byteCount-1]
+                        cmdLine.serial().printf(
+                            "\r\nADDR=0x%2.2x=(0x%2.2x>>1) byteCount:%d RD=%d\r\nI2C MOSI->",
+                            g_I2C_deviceAddress7,
+                            (g_I2C_deviceAddress7 << 1), byteCount, g_I2C_read_count);
+                        for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
+                        {
+                            cmdLine.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
+                        }
+                        //
+                        // TODO: i2c transfer
+                        //const int addr7bit = 0x48;      // 7 bit I2C address
+                        //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
+                        // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
+                        // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
+                        // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
+                        // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
+                        // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
+                        // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
+                        // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
+                        // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
+                        const int addr8bit = g_I2C_deviceAddress7 << 1;             // 8bit I2C address, 0x90
+                        unsigned int misoLength = 0;
+                        bool repeated = (g_I2C_read_count > 0);
+                        //
+                        int writeStatus = i2cMaster.write (addr8bit, mosiData, byteCount, repeated);
+                        switch (writeStatus)
+                        {
+                            case 0: cmdLine.serial().printf(" ack "); break;
+                            case 1: cmdLine.serial().printf(" nack "); break;
+                            default: cmdLine.serial().printf(" {writeStatus 0x%2.2X} ",
+                                                             writeStatus);
+                        }
+                        if (repeated)
+                        {
+                            int readStatus =
+                                i2cMaster.read (addr8bit, misoData, g_I2C_read_count, false);
+                            switch (readStatus)
+                            {
+                                case 1: cmdLine.serial().printf(" nack "); break;
+                                case 0: cmdLine.serial().printf(" ack "); break;
+                                default: cmdLine.serial().printf(" {readStatus 0x%2.2X} ",
+                                                                 readStatus);
+                            }
+                        }
+                        //
+                        if (misoLength > 0)
+                        {
+                            // hex dump misoData[0..byteCount-1]
+                            cmdLine.serial().printf("  MISO<-");
+                            for (unsigned int byteIndex = 0; byteIndex < g_I2C_read_count;
+                                 byteIndex++)
+                            {
+                                cmdLine.serial().printf(" 0x%2.2X", misoData[byteIndex]);
+                            }
+                        }
+                        cmdLine.serial().printf(" ");
+                    }
+                }
+                break;
+                case 'R': case 'r':
+                {
+                    // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
+                    I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
+                    i2cMaster.frequency(g_I2C_SCL_Hz);
+                    // %IR ADDR=? RD=? -- read
+                    // TODO: i2c transfer
+                    //const int addr7bit = 0x48;      // 7 bit I2C address
+                    //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
+                    // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
+                    // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
+                    // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
+                    // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
+                    // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
+                    // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
+                    // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
+                    // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
+                }
+                break;
+                case '^':
+                {
+                    // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
+                    I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
+                    i2cMaster.frequency(g_I2C_SCL_Hz);
+                    // %I^ cmd=? -- i2c_smbus_read_word_data
+                    // TODO: i2c transfer
+                    //const int addr7bit = 0x48;      // 7 bit I2C address
+                    //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
+                    // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
+                    // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
+                    // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
+                    // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
+                    // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
+                    // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
+                    // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
+                    // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
+                }
+                break;
+            }         // switch(cmdLine[2])
+            break;
+#endif
+        //
+#if HAS_SPI // SUPPORT_SPI
+        case 'S': case 's':
+        {
             // %S... -- SPI diagnostics
             // %SC sclk=1Mhz -- SPI configure
             // %SW -- write (write and read)
             // %SR -- read (alias for %SW because SPI always write and read)
-            // A-Z,a-z,0-9 reserved for application use
             //
-            // get pinIndex from cmdLine[2]
-            //int pinIndex = cmdLine[2];
-            // *** warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
-            //int pinIndex = strtoul((char *)((void *)(cmdLine.str()) + 2), NULL, 10); // strtol(str, NULL, 10): get decimal value
-            //                                                        ^
-            char strPinIndex[3];
-            strPinIndex[0] = cmdLine[2];
-            strPinIndex[1] = cmdLine[3];
-            strPinIndex[2] = '\0';
-            int pinIndex = strtoul(strPinIndex, NULL, 10);         // strtol(str, NULL, 10): get decimal value
-            //cmdLine.serial().printf(" pinIndex=%d ", pinIndex);
-            //
-            // get next character
-            switch (cmdLine[1])
+            // Process arguments SCLK=\d+(kHZ|MHZ) CPOL=\d CPHA=\d
+            bool isUpdatedSPIConfig = false;
+            // parse cmdLine arg (CPOL=\d)? --> g_SPI_dataMode | SPI_MODE2
+            // parse cmdLine arg (CPHA=\d)? --> g_SPI_dataMode | SPI_MODE1
+            if (cmdLine.parse_flag("CPOL", g_SPI_dataMode, SPI_MODE2))
+            {
+                isUpdatedSPIConfig = true;
+            }
+            if (cmdLine.parse_flag("CPHA", g_SPI_dataMode, SPI_MODE1))
             {
-#if HAS_digitalInOuts
-                case 'H': case 'h':
+                isUpdatedSPIConfig = true;
+            }
+            if (cmdLine.parse_flag("CS", g_SPI_cs_state, 1))
+            {
+                isUpdatedSPIConfig = true;
+            }
+            // parse cmdLine arg (SCLK=\d+(kHZ|MHZ)?)? --> g_SPI_SCLK_Hz
+            if (cmdLine.parse_frequency_Hz("SCLK", g_SPI_SCLK_Hz))
+            {
+                isUpdatedSPIConfig = true;
+                // TODO1: validate g_SPI_SCLK_Hz against system clock frequency F_CPU
+                if (g_SPI_SCLK_Hz > limit_max_SPI_SCLK_Hz)
                 {
-                    // %Hpin -- digital output high
-#if ARDUINO_STYLE
-                    pinMode(pinIndex, OUTPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
-                    digitalWrite(pinIndex, HIGH);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
-#else
-                    DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
-                    digitalInOutPin.output();
-                    digitalInOutPin.write(1);
-#endif
-                    cmdLine.serial().printf(" digitalInOutPin %d Output High ", pinIndex);
+                    g_SPI_SCLK_Hz = limit_max_SPI_SCLK_Hz;
                 }
-                break;
-                case 'L': case 'l':
-                {
-                    // %Lpin -- digital output low
-#if ARDUINO_STYLE
-                    pinMode(pinIndex, OUTPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
-                    digitalWrite(pinIndex, LOW);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
-#else
-                    DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
-                    digitalInOutPin.output();
-                    digitalInOutPin.write(0);
-#endif
-                    cmdLine.serial().printf(" digitalInOutPin %d Output Low ", pinIndex);
-                }
-                break;
-                case '?':
+                if (g_SPI_SCLK_Hz < limit_min_SPI_SCLK_Hz)
                 {
-                    // %?pin -- digital input
-#if ARDUINO_STYLE
-                    pinMode(pinIndex, INPUT);             // digital pins 0, 1, 2, .. 13, analog input pins A0, A1, .. A5
+                    g_SPI_SCLK_Hz = limit_min_SPI_SCLK_Hz;
+                }
+            }
+            // Update SPI configuration
+            if (isUpdatedSPIConfig)
+            {
+                // %SC sclk=1Mhz -- SPI configure
+                spi_cs = g_SPI_cs_state;
+                spi.format(8,g_SPI_dataMode);             // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=0
+#if APPLICATION_MAX5715
+                g_MAX5715_device.spi_frequency(g_SPI_SCLK_Hz);
+#elif APPLICATION_MAX11131
+                g_MAX11131_device.spi_frequency(g_SPI_SCLK_Hz);
+#elif APPLICATION_MAX5171
+                g_MAX5171_device.spi_frequency(g_SPI_SCLK_Hz);
+#elif APPLICATION_MAX11410
+                g_MAX11410_device.spi_frequency(g_SPI_SCLK_Hz);
+#elif APPLICATION_MAX12345
+                g_MAX12345_device.spi_frequency(g_SPI_SCLK_Hz);
 #else
-                    DigitalInOut& digitalInOutPin = find_digitalInOutPin(pinIndex);
-                    digitalInOutPin.input();
-#endif
-                    serial.printf(" digitalInOutPin %d Input ", pinIndex);
-#if ARDUINO_STYLE
-                    int value = digitalRead(pinIndex);
-#else
-                    int value = digitalInOutPin.read();
-#endif
-                    cmdLine.serial().printf("%d ", value);
-                }
-                break;
+                spi.frequency(g_SPI_SCLK_Hz);             // int SCLK_Hz=1000000 = 1MHz (initial default)
 #endif
                 //
-#if HAS_analogIns
-                case 'A': case 'a':
+                double ideal_divisor = ((double)SystemCoreClock) / g_SPI_SCLK_Hz;
+                int actual_divisor = (int)(ideal_divisor + 0.0);             // frequency divisor truncate
+                double actual_SCLK_Hz = SystemCoreClock / actual_divisor;
+                //
+                // fixed: mbed-os-5.11: [Warning] format '%d' expects argument of type 'int', but argument 6 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
+                cmdLine.serial().printf(
+                    "\r\n %%SC CPOL=%d CPHA=%d CS=%d SCLK=%ld=%1.3fMHz (%1.1fMHz/%1.2f = actual %1.3fMHz) -- SPI config",
+                    ((g_SPI_dataMode & SPI_MODE2) ? 1 : 0),
+                    ((g_SPI_dataMode & SPI_MODE1) ? 1 : 0),
+                    g_SPI_cs_state,
+                    g_SPI_SCLK_Hz,
+                    (g_SPI_SCLK_Hz / 1000000.),
+                    ((double)(SystemCoreClock / 1000000.)),
+                    ideal_divisor,
+                    (actual_SCLK_Hz / 1000000.)
+                    );
+            }
+            // get next character
+            switch (cmdLine[2])
+            {
+                case 'C': case 's':
+                    // %SC sclk=1Mhz -- SPI configure
+                    break;
+                case 'W': case 'R': case 'w': case 'r':
                 {
-                    // %A %Apin -- analog input
-#if analogIn4_IS_HIGH_RANGE_OF_analogIn0
-                    // Platform board uses AIN4,AIN5,.. as high range of AIN0,AIN1,..
-                    for (int pinIndex = 0; pinIndex < 2; pinIndex++)
-                    {
-                        int cPinIndex = '0' + pinIndex;
-                        AnalogIn& analogInPin = find_analogInPin(cPinIndex);
-                        float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
-                        float normValue_0_1 = analogInPin.read();
-                        //
-                        int pinIndexH = pinIndex + 4;
-                        int cPinIndexH = '0' + pinIndexH;
-                        AnalogIn& analogInPinH = find_analogInPin(cPinIndexH);
-                        float adc_full_scale_voltageH = analogInPin_fullScaleVoltage[pinIndexH];
-                        float normValueH_0_1 = analogInPinH.read();
-                        //
-                        cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV  AIN%c = %7.3f%% = %1.3fV  \r\n",
-                                                cPinIndex,
-                                                normValue_0_1 * 100.0,
-                                                normValue_0_1 * adc_full_scale_voltage,
-                                                cPinIndexH,
-                                                normValueH_0_1 * 100.0,
-                                                normValueH_0_1 * adc_full_scale_voltageH
-                                                );
-                    }
-                    for (int pinIndex = 2; pinIndex < 4; pinIndex++)
-                    {
-                        int cPinIndex = '0' + pinIndex;
-                        AnalogIn& analogInPin = find_analogInPin(cPinIndex);
-                        float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
-                        float normValue_0_1 = analogInPin.read();
-                        //
-                        cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV\r\n",
-                                                cPinIndex,
-                                                normValue_0_1 * 100.0,
-                                                normValue_0_1 * adc_full_scale_voltage
-                                                );
-                    }
-#else // analogIn4_IS_HIGH_RANGE_OF_analogIn0
-                    // Platform board uses simple analog inputs
-                    // assume standard Arduino analog inputs A0-A5
-                    for (int pinIndex = 0; pinIndex < 6; pinIndex++)
+                    // %SW -- write (write and read)
+                    // %SR -- read (alias for %SW because SPI always write and read)
+                    // parse cmdLine byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT];
+                    #define MAX_SPI_BYTE_COUNT 32
+                    size_t byteCount = byteCount;
+                    static char mosiData[MAX_SPI_BYTE_COUNT];
+                    static char misoData[MAX_SPI_BYTE_COUNT];
+                    if (cmdLine.parse_byteCount_byteList_hex(byteCount, mosiData,
+                                                             MAX_SPI_BYTE_COUNT))
                     {
-                        int cPinIndex = '0' + pinIndex;
-                        AnalogIn& analogInPin = find_analogInPin(cPinIndex);
-                        float adc_full_scale_voltage = analogInPin_fullScaleVoltage[pinIndex];
-                        float normValue_0_1 = analogInPin.read();
-                        //
-                        cmdLine.serial().printf("AIN%c = %7.3f%% = %1.3fV\r\n",
-                                                cPinIndex,
-                                                normValue_0_1 * 100.0,
-                                                normValue_0_1 * adc_full_scale_voltage
-                                                );
-                    }
-#endif // analogIn4_IS_HIGH_RANGE_OF_analogIn0
-                }
-                break;
-#endif
-                //
-#if HAS_SPI2_MAX541
-                case 'D': case 'd':
-                {
-                    // %D -- DAC output MAX541 (SPI2) -- need cmdLine.parse_float(voltageV)
-                    // MAX541 max541(spi2_max541, spi2_max541_cs);
-                    float voltageV = max541.Get_Voltage();
-                    // if (cmdLine[2] == '+') {
-                    //     // %D+
-                    //     voltageV = voltageV * 1.25f;
-                    //     if (voltageV >= max541.VRef) voltageV = max541.VRef;
-                    //     SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
-                    // }
-                    // else if (cmdLine[2] == '-') {
-                    //     // %D-
-                    //     voltageV = voltageV * 0.75f;
-                    //     if (voltageV < 0.1f) voltageV = 0.1f;
-                    //     SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
-                    // }
-                    if (cmdLine.parse_float("V", voltageV))
-                    {
-                        // %D V=1.234 -- set voltage
-                        max541.Set_Voltage(voltageV);
-                    }
-                    else if (cmdLine.parse_float("TEST", voltageV))
-                    {
-                        // %D TEST=1.234 -- set voltage and compare with AIN0
-                        SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
-                    }
-                    else if (cmdLine.parse_float("CAL", voltageV))
-                    {
-                        // %D CAL=1.234 -- calibrate VRef and compare with AIN0
-
-                        max541.Set_Code(0x8000); // we don't know the fullscale voltage yet, so set code to midscale
-                        double max541_midscale_V = analogInPin_fullScaleVoltage[4] * analogIn4.read(); // TARGET_MAX32630 J1.5 AIN_4 = AIN0 / 5.0     fullscale is 6.0V
-                        const int average_count = 100;
-                        const double average_K = 0.25;
-                        for (int count = 0; count < average_count; count++) {
-                            double measurement_V = analogInPin_fullScaleVoltage[4] * analogIn4.read(); // TARGET_MAX32630 J1.5 AIN_4 = AIN0 / 5.0     fullscale is 6.0V
-                            max541_midscale_V = ((1 - average_K) * max541_midscale_V) + (average_K * measurement_V);
+                        // hex dump mosiData[0..byteCount-1]
+                        cmdLine.serial().printf("\r\nSPI");
+                        if (byteCount > 7) {
+                            cmdLine.serial().printf(" byteCount:%d", byteCount);
+                        }
+                        cmdLine.serial().printf(" MOSI->");
+                        for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
+                        {
+                            cmdLine.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
                         }
-                        max541.VRef = 2.0 * max541_midscale_V;
-                        cmdLine.serial().printf(
-                            "\r\n      MAX541 midscale = %1.3fV, so fullscale = %1.3fV",
-                            max541_midscale_V, max541.VRef);
-                        // Detect whether MAX541 is really connected to MAX32625MBED.AIN0/AIN4
-                        voltageV = 1.0f;
-                        SelfTest_MAX541_Voltage(cmdLine, max541, voltageV);
-                    }
-                    else {
-                        // %D -- print MAX541 DAC status
-                        cmdLine.serial().printf("MAX541 code=0x%4.4x = %1.3fV  VRef=%1.3fV\r\n",
-                                                max541.Get_Code(), max541.Get_Voltage(), max541.VRef);
+                        spi_cs = 0;
+                        unsigned int numBytesTransferred =
+                            spi.write(mosiData, byteCount, misoData, byteCount);
+                        spi_cs = 1;
+                        // hex dump misoData[0..byteCount-1]
+                        cmdLine.serial().printf("  MISO<-");
+                        for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred;
+                             byteIndex++)
+                        {
+                            cmdLine.serial().printf(" 0x%2.2X", misoData[byteIndex]);
+                        }
+                        cmdLine.serial().printf(" ");
                     }
                 }
                 break;
-#endif
+            }             // switch(cmdLine[2])
+        }             // case 'S': // %S... -- SPI diagnostics
+        break;
+#endif
+        //
+        // A-Z,a-z,0-9 reserved for application use
+    }         // switch(cmdLine[1])
+} // end void pinsMonitor_submenu_onEOLcommandParser(CmdLine & cmdLine)
 
-                //
-#if HAS_I2C // SUPPORT_I2C
-                case 'I': case 'i':
-                    // %I... -- I2C diagnostics
-                    // %IP -- I2C probe
-                    // %IC scl=100khz ADDR=? -- I2C configure
-                    // %IW byte byte ... byte RD=? ADDR=0x -- write
-                    // %IR ADDR=? RD=? -- read
-                    // %I^ cmd=? -- i2c_smbus_read_word_data
-                    // get next character
-                    // TODO: parse cmdLine arg (ADDR=\d+)? --> g_I2C_deviceAddress7
-                    cmdLine.parse_byte_hex("ADDR", g_I2C_deviceAddress7);
-                    // TODO: parse cmdLine arg (RD=\d)? --> g_I2C_read_count
-                    g_I2C_read_count = 0;         // read count must be reset every command
-                    cmdLine.parse_byte_dec("RD", g_I2C_read_count);
-                    // TODO: parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress
-                    cmdLine.parse_byte_hex("CMD", g_I2C_command_regAddress);
-                    switch (cmdLine[2])
-                    {
-                        case 'P': case 'p':
-                        {
-                            // %IP -- I2C probe
-                            HuntAttachedI2CDevices(cmdLine, 0x03, 0x77);
-                        }
-                        break;
-                        case 'C': case 'c':
-                        {
-                            bool isUpdatedI2CConfig = false;
-                            // %IC scl=100khz ADDR=? -- I2C configure
-                            // parse cmdLine arg (SCL=\d+(kHZ|MHZ)?)? --> g_I2C_SCL_Hz
-                            if (cmdLine.parse_frequency_Hz("SCL", g_I2C_SCL_Hz))
-                            {
-                                isUpdatedI2CConfig = true;
-                                // TODO1: validate g_I2C_SCL_Hz against system clock frequency F_CPU
-                                if (g_I2C_SCL_Hz > limit_max_I2C_SCL_Hz)
-                                {
-                                    g_I2C_SCL_Hz = limit_max_I2C_SCL_Hz;
-                                }
-                                if (g_I2C_SCL_Hz < limit_min_I2C_SCL_Hz)
-                                {
-                                    g_I2C_SCL_Hz = limit_min_I2C_SCL_Hz;
-                                }
-                            }
-                            if (isUpdatedI2CConfig)
-                            {
-                                // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
-                                I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
-                                i2cMaster.frequency(g_I2C_SCL_Hz);
-                                i2cMaster.start();
-                                i2cMaster.stop();
-                                i2cMaster.frequency(g_I2C_SCL_Hz);
-                                cmdLine.serial().printf(
-                                    "\r\n %%IC ADDR=0x%2.2x=(0x%2.2x>>1) SCL=%d=%1.3fkHz -- I2C config",
-                                    g_I2C_deviceAddress7, (g_I2C_deviceAddress7 << 1), g_I2C_SCL_Hz,
-                                    (g_I2C_SCL_Hz / 1000.));
-                                i2cMaster.start();
-                                i2cMaster.stop();
-                            }
-                        }
-                        break;
-                        case 'W': case 'w':
-                        {
-                            // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
-                            I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
-                            i2cMaster.frequency(g_I2C_SCL_Hz);
-                            // %IW byte byte ... byte RD=? ADDR=0x -- write
-                            // parse cmdLine byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT];
-                            #define MAX_I2C_BYTE_COUNT 32
-                            size_t byteCount = byteCount;
-                            static char mosiData[MAX_I2C_BYTE_COUNT];
-                            static char misoData[MAX_I2C_BYTE_COUNT];
-                            if (cmdLine.parse_byteCount_byteList_hex(byteCount, mosiData,
-                                                                     MAX_I2C_BYTE_COUNT))
-                            {
-                                // hex dump mosiData[0..byteCount-1]
-                                cmdLine.serial().printf(
-                                    "\r\nADDR=0x%2.2x=(0x%2.2x>>1) byteCount:%d RD=%d\r\nI2C MOSI->",
-                                    g_I2C_deviceAddress7,
-                                    (g_I2C_deviceAddress7 << 1), byteCount, g_I2C_read_count);
-                                for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
-                                {
-                                    cmdLine.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
-                                }
-                                //
-                                // TODO: i2c transfer
-                                //const int addr7bit = 0x48;      // 7 bit I2C address
-                                //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
-                                // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
-                                // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
-                                // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
-                                // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
-                                // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
-                                // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
-                                // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
-                                // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
-                                const int addr8bit = g_I2C_deviceAddress7 << 1;             // 8bit I2C address, 0x90
-                                unsigned int misoLength = 0;
-                                bool repeated = (g_I2C_read_count > 0);
-                                //
-                                int writeStatus = i2cMaster.write (addr8bit, mosiData, byteCount, repeated);
-                                switch (writeStatus)
-                                {
-                                    case 0: cmdLine.serial().printf(" ack "); break;
-                                    case 1: cmdLine.serial().printf(" nack "); break;
-                                    default: cmdLine.serial().printf(" {writeStatus 0x%2.2X} ",
-                                                                     writeStatus);
-                                }
-                                if (repeated)
-                                {
-                                    int readStatus =
-                                        i2cMaster.read (addr8bit, misoData, g_I2C_read_count, false);
-                                    switch (readStatus)
-                                    {
-                                        case 1: cmdLine.serial().printf(" nack "); break;
-                                        case 0: cmdLine.serial().printf(" ack "); break;
-                                        default: cmdLine.serial().printf(" {readStatus 0x%2.2X} ",
-                                                                         readStatus);
-                                    }
-                                }
-                                //
-                                if (misoLength > 0)
-                                {
-                                    // hex dump misoData[0..byteCount-1]
-                                    cmdLine.serial().printf("  MISO<-");
-                                    for (unsigned int byteIndex = 0; byteIndex < g_I2C_read_count;
-                                         byteIndex++)
-                                    {
-                                        cmdLine.serial().printf(" 0x%2.2X", misoData[byteIndex]);
-                                    }
-                                }
-                                cmdLine.serial().printf(" ");
-                            }
-                        }
-                        break;
-                        case 'R': case 'r':
-                        {
-                            // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
-                            I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
-                            i2cMaster.frequency(g_I2C_SCL_Hz);
-                            // %IR ADDR=? RD=? -- read
-                            // TODO: i2c transfer
-                            //const int addr7bit = 0x48;      // 7 bit I2C address
-                            //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
-                            // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
-                            // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
-                            // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
-                            // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
-                            // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
-                            // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
-                            // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
-                            // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
-                        }
-                        break;
-                        case '^':
-                        {
-                            // declare in narrower scope: MAX32625MBED I2C i2cMaster(...)
-                            I2C i2cMaster(I2C0_SDA, I2C0_SCL);             // sda scl TARGET_MAX32635MBED: P1_6, P1_7 Arduino 10-pin header
-                            i2cMaster.frequency(g_I2C_SCL_Hz);
-                            // %I^ cmd=? -- i2c_smbus_read_word_data
-                            // TODO: i2c transfer
-                            //const int addr7bit = 0x48;      // 7 bit I2C address
-                            //const int addr8bit = 0x48 << 1; // 8bit I2C address, 0x90
-                            // /* int  */   i2cMaster.read (int addr8bit, char *data, int length, bool repeated=false) // Read from an I2C slave.
-                            // /* int  */   i2cMaster.read (int ack) // Read a single byte from the I2C bus.
-                            // /* int  */   i2cMaster.write (int addr8bit, const char *data, int length, bool repeated=false) // Write to an I2C slave.
-                            // /* int  */   i2cMaster.write (int data) // Write single byte out on the I2C bus.
-                            // /* void */   i2cMaster.start (void) // Creates a start condition on the I2C bus.
-                            // /* void */   i2cMaster.stop (void) // Creates a stop condition on the I2C bus.
-                            // /* int */    i2cMaster.transfer (int addr8bit, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event=I2C_EVENT_TRANSFER_COMPLETE, bool repeated=false) // Start nonblocking I2C transfer. More...
-                            // /* void */   i2cMaster.abort_transfer () // Abort the ongoing I2C transfer. More...
-                        }
-                        break;
-                    }         // switch(cmdLine[2])
-                    break;
-#endif
-                //
-#if HAS_SPI // SUPPORT_SPI
-                case 'S': case 's':
-                {
-                    // %S... -- SPI diagnostics
-                    // %SC sclk=1Mhz -- SPI configure
-                    // %SW -- write (write and read)
-                    // %SR -- read (alias for %SW because SPI always write and read)
-                    //
-                    // Process arguments SCLK=\d+(kHZ|MHZ) CPOL=\d CPHA=\d
-                    bool isUpdatedSPIConfig = false;
-                    // parse cmdLine arg (CPOL=\d)? --> g_SPI_dataMode | SPI_MODE2
-                    // parse cmdLine arg (CPHA=\d)? --> g_SPI_dataMode | SPI_MODE1
-                    if (cmdLine.parse_flag("CPOL", g_SPI_dataMode, SPI_MODE2))
-                    {
-                        isUpdatedSPIConfig = true;
-                    }
-                    if (cmdLine.parse_flag("CPHA", g_SPI_dataMode, SPI_MODE1))
-                    {
-                        isUpdatedSPIConfig = true;
-                    }
-                    if (cmdLine.parse_flag("CS", g_SPI_cs_state, 1))
-                    {
-                        isUpdatedSPIConfig = true;
-                    }
-                    // parse cmdLine arg (SCLK=\d+(kHZ|MHZ)?)? --> g_SPI_SCLK_Hz
-                    if (cmdLine.parse_frequency_Hz("SCLK", g_SPI_SCLK_Hz))
-                    {
-                        isUpdatedSPIConfig = true;
-                        // TODO1: validate g_SPI_SCLK_Hz against system clock frequency F_CPU
-                        if (g_SPI_SCLK_Hz > limit_max_SPI_SCLK_Hz)
-                        {
-                            g_SPI_SCLK_Hz = limit_max_SPI_SCLK_Hz;
-                        }
-                        if (g_SPI_SCLK_Hz < limit_min_SPI_SCLK_Hz)
-                        {
-                            g_SPI_SCLK_Hz = limit_min_SPI_SCLK_Hz;
-                        }
-                    }
-                    // Update SPI configuration
-                    if (isUpdatedSPIConfig)
-                    {
-                        // %SC sclk=1Mhz -- SPI configure
-                        spi_cs = g_SPI_cs_state;
-                        spi.format(8,g_SPI_dataMode);             // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=0
-#if APPLICATION_MAX5715
-                        g_MAX5715_device.spi_frequency(g_SPI_SCLK_Hz);
-#elif APPLICATION_MAX11131
-                        g_MAX11131_device.spi_frequency(g_SPI_SCLK_Hz);
-#elif APPLICATION_MAX5171
-                        g_MAX5171_device.spi_frequency(g_SPI_SCLK_Hz);
-#elif APPLICATION_MAX11410
-                        g_MAX11410_device.spi_frequency(g_SPI_SCLK_Hz);
-#elif APPLICATION_MAX12345
-                        g_MAX12345_device.spi_frequency(g_SPI_SCLK_Hz);
-#else
-                        spi.frequency(g_SPI_SCLK_Hz);             // int SCLK_Hz=1000000 = 1MHz (initial default)
-#endif
-                        //
-                        double ideal_divisor = ((double)SystemCoreClock) / g_SPI_SCLK_Hz;
-                        int actual_divisor = (int)(ideal_divisor + 0.0);             // frequency divisor truncate
-                        double actual_SCLK_Hz = SystemCoreClock / actual_divisor;
-                        //
-                        // fixed: mbed-os-5.11: [Warning] format '%d' expects argument of type 'int', but argument 6 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
-                        cmdLine.serial().printf(
-                            "\r\n %%SC CPOL=%d CPHA=%d CS=%d SCLK=%ld=%1.3fMHz (%1.1fMHz/%1.2f = actual %1.3fMHz) -- SPI config",
-                            ((g_SPI_dataMode & SPI_MODE2) ? 1 : 0),
-                            ((g_SPI_dataMode & SPI_MODE1) ? 1 : 0),
-                            g_SPI_cs_state,
-                            g_SPI_SCLK_Hz,
-                            (g_SPI_SCLK_Hz / 1000000.),
-                            ((double)(SystemCoreClock / 1000000.)),
-                            ideal_divisor,
-                            (actual_SCLK_Hz / 1000000.)
-                            );
-                    }
-                    // get next character
-                    switch (cmdLine[2])
-                    {
-                        case 'C': case 's':
-                            // %SC sclk=1Mhz -- SPI configure
-                            break;
-                        case 'W': case 'R': case 'w': case 'r':
-                        {
-                            // %SW -- write (write and read)
-                            // %SR -- read (alias for %SW because SPI always write and read)
-                            // parse cmdLine byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT];
-                            #define MAX_SPI_BYTE_COUNT 32
-                            size_t byteCount = byteCount;
-                            static char mosiData[MAX_SPI_BYTE_COUNT];
-                            static char misoData[MAX_SPI_BYTE_COUNT];
-                            if (cmdLine.parse_byteCount_byteList_hex(byteCount, mosiData,
-                                                                     MAX_SPI_BYTE_COUNT))
-                            {
-                                // hex dump mosiData[0..byteCount-1]
-                                cmdLine.serial().printf("\r\nSPI");
-                                if (byteCount > 7) {
-                                    cmdLine.serial().printf(" byteCount:%d", byteCount);
-                                }
-                                cmdLine.serial().printf(" MOSI->");
-                                for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
-                                {
-                                    cmdLine.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
-                                }
-                                spi_cs = 0;
-                                unsigned int numBytesTransferred =
-                                    spi.write(mosiData, byteCount, misoData, byteCount);
-                                spi_cs = 1;
-                                // hex dump misoData[0..byteCount-1]
-                                cmdLine.serial().printf("  MISO<-");
-                                for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred;
-                                     byteIndex++)
-                                {
-                                    cmdLine.serial().printf(" 0x%2.2X", misoData[byteIndex]);
-                                }
-                                cmdLine.serial().printf(" ");
-                            }
-                        }
-                        break;
-                    }             // switch(cmdLine[2])
-                }             // case 'S': // %S... -- SPI diagnostics
-                break;
-#endif
-                //
-                // A-Z,a-z,0-9 reserved for application use
-            }         // switch(cmdLine[1])
-        }
-        break;         // case '%'
-#endif // APPLICATION_ArduinoPinsMonitor
-       //
-       // Application-specific commands here
-       // alphanumeric command codes A-Z,a-z,0-9 reserved for application use
-       //
-#if APPLICATION_ArduinoPinsMonitor
-#endif // APPLICATION_ArduinoPinsMonitor
 
-#if APPLICATION_MAX5715 // main_menu_onEOLcommandParser
+//--------------------------------------------------
+#if 0 // APPLICATION_MAX5715 // MAX5715_menu_onEOLcommandParser moved to Test_Menu_MAX5715.cpp
+bool MAX5715_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    switch (cmdLine[0])
+    {
         case '0':
         {
             // recommended for hex command codes 00..0F
@@ -4411,6 +4368,7 @@
             }
             cmdLine.serial().printf("CODEn ch=%d code=%d", ch, code);
             g_MAX5715_device.CODEn(ch, code);
+            return true; // command was handled by MAX5715
         }
         break;
         case '1':
@@ -4424,6 +4382,7 @@
             }
             cmdLine.serial().printf("LOADn ch=%d", ch);
             g_MAX5715_device.LOADn(ch);
+            return true; // command was handled by MAX5715
         }
         break;
         case '2':
@@ -4441,6 +4400,7 @@
             }
             cmdLine.serial().printf("CODEnLOADall ch=%d code=%d", ch, code);
             g_MAX5715_device.CODEnLOADall(ch, code);
+            return true; // command was handled by MAX5715
         }
         break;
         case '3':
@@ -4458,6 +4418,7 @@
             }
             cmdLine.serial().printf("CODEnLOADn ch=%d code=%d", ch, code);
             g_MAX5715_device.CODEnLOADn(ch, code);
+            return true; // command was handled by MAX5715
         }
         break;
         case '4':
@@ -4474,6 +4435,7 @@
                     g_MAX5715_device.POWER(g_MAX5715_device.
                                            channels_bitmask_DCBA,
                                            MAX5715::POWERn_Normal);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '1':
@@ -4485,6 +4447,7 @@
                     g_MAX5715_device.POWER(g_MAX5715_device.
                                            channels_bitmask_DCBA,
                                            MAX5715::POWERn_PD1k);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '2':
@@ -4496,6 +4459,7 @@
                     g_MAX5715_device.POWER(g_MAX5715_device.
                                            channels_bitmask_DCBA,
                                            MAX5715::POWERn_PD100k);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '3':
@@ -4507,6 +4471,7 @@
                     g_MAX5715_device.POWER(g_MAX5715_device.
                                            channels_bitmask_DCBA,
                                            MAX5715::POWERn_PDHiZ);
+                    return true; // command was handled by MAX5715
                 }
                 break;
             }
@@ -4523,6 +4488,7 @@
                     // cmdLine.serial().printf("\r\n 50 -- SW_CLEAR");
                     cmdLine.serial().printf("SW_CLEAR");
                     g_MAX5715_device.SW_CLEAR();
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '1':
@@ -4530,6 +4496,7 @@
                     // cmdLine.serial().printf("\r\n 51 -- SW_RESET");
                     cmdLine.serial().printf("SW_RESET");
                     g_MAX5715_device.SW_RESET();
+                    return true; // command was handled by MAX5715
                 }
                 break;
             }
@@ -4549,6 +4516,7 @@
                         channels_bitmask_DCBA);
                     g_MAX5715_device.CONFIGn_LATCHED(g_MAX5715_device.
                                                      channels_bitmask_DCBA);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '1':
@@ -4560,6 +4528,7 @@
                         channels_bitmask_DCBA);
                     g_MAX5715_device.CONFIGn_TRANSPARENT(
                         g_MAX5715_device.channels_bitmask_DCBA);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '8':
@@ -4568,6 +4537,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_CONFIGall_LATCHED()");
                     g_MAX5715_device.CONFIGall_LATCHED();
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '9':
@@ -4576,6 +4546,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_CONFIGall_TRANSPARENT()");
                     g_MAX5715_device.CONFIGall_TRANSPARENT();
+                    return true; // command was handled by MAX5715
                 }
                 break;
             }
@@ -4592,6 +4563,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_EXT)");
                     g_MAX5715_device.REF(MAX5715::REF_EXT);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '1':
@@ -4600,6 +4572,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_2V500)");
                     g_MAX5715_device.REF(MAX5715::REF_2V500);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '2':
@@ -4608,6 +4581,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_2V048)");
                     g_MAX5715_device.REF(MAX5715::REF_2V048);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '3':
@@ -4616,6 +4590,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_4V096)");
                     g_MAX5715_device.REF(MAX5715::REF_4V096);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '4':
@@ -4624,6 +4599,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_AlwaysOn_EXT)");
                     g_MAX5715_device.REF(MAX5715::REF_AlwaysOn_EXT);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '5':
@@ -4632,6 +4608,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_AlwaysOn_2V500)");
                     g_MAX5715_device.REF(MAX5715::REF_AlwaysOn_2V500);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '6':
@@ -4640,6 +4617,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_AlwaysOn_2V048)");
                     g_MAX5715_device.REF(MAX5715::REF_AlwaysOn_2V048);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '7':
@@ -4648,6 +4626,7 @@
                     cmdLine.serial().printf(
                         "MAX5715_REF(REF_AlwaysOn_4V096)");
                     g_MAX5715_device.REF(MAX5715::REF_AlwaysOn_4V096);
+                    return true; // command was handled by MAX5715
                 }
                 break;
             }
@@ -4669,6 +4648,7 @@
                     }
                     cmdLine.serial().printf("CODEall code=%d", code);
                     g_MAX5715_device.CODEall(code);
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '1':
@@ -4676,6 +4656,7 @@
                     // TODO: cmdLine.serial().printf("\r\n 81 -- LOADall");
                     cmdLine.serial().printf("LOADall");
                     g_MAX5715_device.LOADall();
+                    return true; // command was handled by MAX5715
                 }
                 break;
                 case '2':
@@ -4687,6 +4668,7 @@
                     }
                     cmdLine.serial().printf("CODEallLOADall code=%d", code);
                     g_MAX5715_device.CODEallLOADall(code);
+                    return true; // command was handled by MAX5715
                 }
                 break;
             }
@@ -4708,7 +4690,7 @@
                     cmdLine_DAPLINKserial.serial().printf("\r\n ignore AT command \"%s\"\r\n", cmdLine.str());
 # endif // HAS_DAPLINK_SERIAL
                     // AT command: skip the prompt to avoid confusing modem detector
-                    return;
+                    return false; // command not handled
 #endif // IGNORE_AT_COMMANDS
             }
         }
@@ -4738,6 +4720,7 @@
                     g_MAX5715_device.CLRboutputValue(0);         // GPIOoutputCLRb(int isLogicHigh);
                     break;
             }
+            return true; // command was handled by MAX5715
         }
         break;
         case 'd': case 'D':
@@ -4774,6 +4757,7 @@
                     g_MAX5715_device.LDACboutputValue(0);         // GPIOoutputLDACb(int isLogicHigh);
                     break;
             }
+            return true; // command was handled by MAX5715
         }
         break;
         case 'x': case 'X':
@@ -4848,11 +4832,20 @@
             //
             cmdLine.serial().printf("VRef=%5.3fV\r\n", g_MAX5715_device.VRef);
             // dtostrf width and precision: 3.3V / 1024 LSB = 0.00322265625 volts per LSB
+            return true; // command was handled by MAX5715
         }
         break;
-#endif // APPLICATION_MAX5715
+    } // end switch (cmdLine[0])
+    return false; // command not handled by MAX5715
+} // end bool MAX5715_menu_onEOLcommandParser(CmdLine & cmdLine)
+#endif
 
-#if APPLICATION_MAX11131 // main_menu_onEOLcommandParser
+//--------------------------------------------------
+#if 0 // APPLICATION_MAX11131 // MAX11131_menu_onEOLcommandParser moved to Test_Menu_MAX11131.cpp
+bool MAX11131_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    switch (cmdLine[0])
+    {
         case '0':
         {
             // recommended for hex command codes 00..0F
@@ -4886,6 +4879,7 @@
                 //
                 AINcode_print_value_chanID(cmdLine, g_MAX11131_device.NumWords);
             }
+            return true; // command was handled by MAX11131
         }
         break;
         case '1':
@@ -4918,6 +4912,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_externalClock(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '2':
@@ -4967,6 +4962,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_chanID_mean(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '3':
@@ -5009,6 +5005,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_chanID(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '4':
@@ -5045,6 +5042,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_externalClock(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '5':
@@ -5087,6 +5085,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_chanID(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '6':
@@ -5123,6 +5122,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_externalClock(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '7':
@@ -5166,6 +5166,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_chanID(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '8':
@@ -5200,6 +5201,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_externalClock(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case '9':
@@ -5247,6 +5249,7 @@
             // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
             //
             AINcode_print_value_externalClock(cmdLine, g_MAX11131_device.NumWords);
+            return true; // command was handled by MAX11131
         }
         break;
         case 'a': case 'A':
@@ -5260,7 +5263,7 @@
                     cmdLine_DAPLINKserial.serial().printf("\r\n ignore AT command \"%s\"\r\n", cmdLine.str());
 # endif // HAS_DAPLINK_SERIAL
                     // AT command: skip the prompt to avoid confusing modem detector
-                    return;
+                    return false; // command not handled
 #endif // IGNORE_AT_COMMANDS
             }
         }
@@ -5338,6 +5341,7 @@
             // else if (cmd1 == 'R') {
             //     MAX11131_Reconfigure_DifferentialBipolarFS2Vref(channelId_0_15);
             // }
+            return true; // command was handled by MAX11131
         }
         break;
         case '@':
@@ -5421,6 +5425,7 @@
             cmdLine.serial().printf("VRef=%5.3fV\r\n", g_MAX11131_device.VRef);
             // dtostrf width and precision: 3.3V / 1024 LSB = 0.00322265625 volts per LSB
             //
+            return true; // command was handled by MAX11131
         }
             //case '&':
             //{
@@ -5446,10 +5451,17 @@
 #endif // IGNORE_AT_COMMANDS
         }
         break;
-#endif // APPLICATION_MAX11131
+    } // end switch (cmdLine[0])
+    return false; // command not handled
+} // end bool MAX11131_menu_onEOLcommandParser(CmdLine & cmdLine)
+#endif
 
-#if APPLICATION_MAX5171 // main_menu_onEOLcommandParser
-        // MAX5171 main_menu_onEOLcommandParser
+//--------------------------------------------------
+#if 0 // APPLICATION_MAX5171 // MAX5171_menu_onEOLcommandParser moved to Test_Menu_MAX5171.cpp
+bool MAX5171_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    switch (cmdLine[0])
+    {
         case '0':
         {
             // recommended for hex command codes 10..1F
@@ -5460,6 +5472,7 @@
             }
             cmdLine.serial().printf("CODE code=%d", code);
             g_MAX5171_device.CODE(code);
+            return true; // command was handled by MAX5171
         }
         break;
         case '4':
@@ -5472,6 +5485,7 @@
             }
             cmdLine.serial().printf("CODE_LOAD code=%d", code);
             g_MAX5171_device.CODE_LOAD(code);
+            return true; // command was handled by MAX5171
         }
         break;
         case '8':
@@ -5480,6 +5494,7 @@
             //~ cmdLine.serial().printf("\r\n 8 -- LOAD");
             cmdLine.serial().printf("LOAD");
             g_MAX5171_device.LOAD();
+            return true; // command was handled by MAX5171
         }
         break;
         case 'c': case 'C':
@@ -5488,6 +5503,7 @@
             //~ cmdLine.serial().printf("\r\n c -- NOP");
             cmdLine.serial().printf("NOP");
             g_MAX5171_device.NOP();
+            return true; // command was handled by MAX5171
         }
         break;
         case 'd': case 'D':
@@ -5496,6 +5512,7 @@
             //~ cmdLine.serial().printf("\r\n d -- SHUTDOWN");
             cmdLine.serial().printf("SHUTDOWN");
             g_MAX5171_device.SHUTDOWN();
+            return true; // command was handled by MAX5171
         }
         break;
         case 'e': case 'E':
@@ -5508,6 +5525,7 @@
                     //~ cmdLine.serial().printf("\r\n e0 -- UPO_LOW");
                     cmdLine.serial().printf("UPO_LOW");
                     g_MAX5171_device.UPO_LOW();
+                    return true; // command was handled by MAX5171
                 }
                 break;
                 case '8':
@@ -5516,6 +5534,7 @@
                     //~ cmdLine.serial().printf("\r\n e8 -- UPO_HIGH");
                     cmdLine.serial().printf("UPO_HIGH");
                     g_MAX5171_device.UPO_HIGH();
+                    return true; // command was handled by MAX5171
                 }
                 break;
             }
@@ -5531,6 +5550,7 @@
                     //~ cmdLine.serial().printf("\r\n f0 -- MODE1_DOUT_SCLK_RISING_EDGE");
                     cmdLine.serial().printf("MODE1_DOUT_SCLK_RISING_EDGE");
                     g_MAX5171_device.MODE1_DOUT_SCLK_RISING_EDGE();
+                    return true; // command was handled by MAX5171
                 }
                 break;
                 case '8':
@@ -5539,6 +5559,7 @@
                     //~ cmdLine.serial().printf("\r\n f8 -- MODE0_DOUT_SCLK_FALLING_EDGE");
                     cmdLine.serial().printf("MODE0_DOUT_SCLK_FALLING_EDGE");
                     g_MAX5171_device.MODE0_DOUT_SCLK_FALLING_EDGE();
+                    return true; // command was handled by MAX5171
                 }
                 break;
             }
@@ -5591,10 +5612,17 @@
 #endif // IGNORE_AT_COMMANDS
         }
         break;
-#endif // APPLICATION_MAX5171
+    } // end switch (cmdLine[0])
+    return false; // command not handled
+} // end bool MAX5171_menu_onEOLcommandParser(CmdLine & cmdLine)
+#endif
 
-
-#if APPLICATION_MAX11410 // main_menu_onEOLcommandParser
+//--------------------------------------------------
+#if 0 // APPLICATION_MAX11410 // MAX11410_menu_onEOLcommandParser moved to Test_Menu_MAX11410.cpp
+bool MAX11410_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    switch (cmdLine[0])
+    {
         // TODO1: MAX11410 main_menu_onEOLcommandParser
         case '0':
         {
@@ -5615,6 +5643,7 @@
             cmdLine.serial().printf("CODEnLOADn ch=%d code=%d", ch, code);
             MAX5715_CODEnLOADn(ch, code);
             cmdLine.serial().printf("\r\n placeholder");
+            return true; // command was handled by MAX11410
         }
         break;
         case '1':
@@ -5734,10 +5763,19 @@
 #endif // IGNORE_AT_COMMANDS
         }
         break;
-#endif // APPLICATION_MAX11410
+    } // end switch (cmdLine[0])
+    return false; // command not handled
+} // end bool MAX11410_menu_onEOLcommandParser(CmdLine & cmdLine)
+#endif
 
 
-#if APPLICATION_MAX12345 // main_menu_onEOLcommandParser
+//--------------------------------------------------
+#if APPLICATION_MAX12345 // MAX12345_menu_onEOLcommandParser
+bool MAX12345_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    switch (cmdLine[0])
+    {
+        // TODO1: MAX12345 main_menu_onEOLcommandParser
         case '0':
         {
             // recommended for hex command codes 00..0F
@@ -5757,6 +5795,7 @@
             cmdLine.serial().printf("CODEnLOADn ch=%d code=%d", ch, code);
             MAX5715_CODEnLOADn(ch, code);
             cmdLine.serial().printf("\r\n placeholder");
+            return true; // command was handled by MAX12345
         }
         break;
         case '1':
@@ -5876,17 +5915,97 @@
 #endif // IGNORE_AT_COMMANDS
         }
         break;
-#endif // APPLICATION_MAX12345
+    } // end switch (cmdLine[0])
+    return false; // command not handled
+} // end bool MAX12345_menu_onEOLcommandParser(CmdLine & cmdLine)
+#endif
+
+
+//--------------------------------------------------
+// main menu command-line parser
+// invoked by CmdLine::append(char ch) or CmdLine::idleAppendIfReadable()
+void main_menu_onEOLcommandParser(CmdLine & cmdLine)
+{
+    // DIAGNOSTIC: print line buffer
+    //~ cmdLine.serial().printf("\r\nmain_menu_onEOLcommandParser: ~%s~\r\n", cmdLine.str());
+    //
+    switch (cmdLine[0])
+    {
+        case '?':
+            main_menu_status(cmdLine);
+            main_menu_help(cmdLine);
+            // print command prompt
+            //cmdLine.serial().printf("\r\n>");
+            break;
+        case '\r': case '\n':     // ignore blank line
+        case '\0':     // ignore empty line
+        case '#':     // ignore comment line
+            // # -- lines beginning with # are comments
+            main_menu_status(cmdLine);
+            //~ main_menu_help(cmdLine);
+            // print command prompt
+            //cmdLine.serial().printf("\r\n>");
+            break;
+#if ECHO_EOF_ON_EOL
+        case '\x04':     // Unicode (U+0004) EOT END OF TRANSMISSION = CTRL+D as EOF end of file
+            cmdLine.serial().printf("\x04");     // immediately echo EOF for test scripting
+            diagnostic_led_EOF();
+            break;
+        case '\x1a':     // Unicode (U+001A) SUB SUBSTITUTE = CTRL+Z as EOF end of file
+            cmdLine.serial().printf("\x1a");     // immediately echo EOF for test scripting
+            diagnostic_led_EOF();
+            break;
+#endif
+#if APPLICATION_ArduinoPinsMonitor
+        case '.':
+        {
+            // . -- SelfTest
+            cmdLine.serial().printf("SelfTest()");
+            SelfTest(cmdLine);
+        }
+        break;
+        case '%':
+        {
+            pinsMonitor_submenu_onEOLcommandParser(cmdLine);
+        }
+        break;         // case '%'
+#endif // APPLICATION_ArduinoPinsMonitor
+       //
+       // Application-specific commands here
+       // alphanumeric command codes A-Z,a-z,0-9 reserved for application use
+       //
+#if APPLICATION_ArduinoPinsMonitor
+#endif // APPLICATION_ArduinoPinsMonitor
 
         //
         // TODO1: add new commands here
         //
         default:
-            cmdLine.serial().printf("\r\n unknown command 0x%2.2x \"%s\"\r\n", cmdLine.str()[0], cmdLine.str());
+#if APPLICATION_MAX5715 // main_menu_onEOLcommandParser print command prompt
+            extern bool MAX5715_menu_onEOLcommandParser(CmdLine & cmdLine); // defined in Test_Menu_MAX5715.cpp
+            if (!MAX5715_menu_onEOLcommandParser(cmdLine))
+#elif APPLICATION_MAX11131 // main_menu_onEOLcommandParser print command prompt
+            extern bool MAX11131_menu_onEOLcommandParser(CmdLine & cmdLine); // defined in Test_Menu_MAX11131.cpp
+            if (!MAX11131_menu_onEOLcommandParser(cmdLine))
+#elif APPLICATION_MAX5171 // main_menu_onEOLcommandParser print command prompt
+            extern bool MAX5171_menu_onEOLcommandParser(CmdLine & cmdLine); // defined in Test_Menu_MAX5171.cpp
+            if (!MAX5171_menu_onEOLcommandParser(cmdLine))
+#elif APPLICATION_MAX11410 // main_menu_onEOLcommandParser print command prompt
+            extern bool MAX11410_menu_onEOLcommandParser(CmdLine & cmdLine); // defined in Test_Menu_MAX11410.cpp
+            if (!MAX11410_menu_onEOLcommandParser(cmdLine))
+#elif APPLICATION_MAX12345 // main_menu_onEOLcommandParser print command prompt
+            extern bool MAX12345_menu_onEOLcommandParser(CmdLine & cmdLine); // defined in Test_Menu_MAX12345.cpp
+            if (!MAX12345_menu_onEOLcommandParser(cmdLine))
+#else
+            if (0) // not_handled_by_device_submenu
+#endif
+            {
+                cmdLine.serial().printf("\r\n unknown command 0x%2.2x \"%s\"\r\n", cmdLine.str()[0], cmdLine.str());
 # if HAS_DAPLINK_SERIAL
-            cmdLine_DAPLINKserial.serial().printf("\r\n unknown command 0x%2.2x \"%s\"\r\n",
-                                                  cmdLine.str()[0], cmdLine.str());
+                cmdLine_DAPLINKserial.serial().printf("\r\n unknown command 0x%2.2x \"%s\"\r\n",
+                                                      cmdLine.str()[0], cmdLine.str());
 # endif // HAS_DAPLINK_SERIAL
+            }
     }     // switch (cmdLine[0])
 //
 // print command prompt
@@ -5903,7 +6022,7 @@
 #else
     cmdLine.serial().printf("\r\n> ");
 #endif
-}
+} // end void main_menu_onEOLcommandParser(CmdLine & cmdLine)
 
 //--------------------------------------------------
 void InitializeConfiguration()