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:
4:d9b05924ad4c
Parent:
3:9055e17e181a
Child:
5:aaf8b5f5fda1
diff -r 9055e17e181a -r d9b05924ad4c DataLogger_Internal.cpp
--- a/DataLogger_Internal.cpp	Wed Nov 25 06:18:08 2020 +0000
+++ b/DataLogger_Internal.cpp	Sun Nov 29 02:34:50 2020 +0000
@@ -1556,6 +1556,40 @@
 
 
 //--------------------------------------------------
+// TODO support CmdLine command menus (like on Serial_Tester)
+#ifndef USE_CMDLINE_MENUS
+#define USE_CMDLINE_MENUS 1
+//~ #undef USE_CMDLINE_MENUS
+#endif
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+#include "CmdLine.h"
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+extern CmdLine cmdLine; // declared later
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+//--------------------------------------------------
+// Datalog trigger types
+#ifndef USE_DATALOGGER_TRIGGER
+#define USE_DATALOGGER_TRIGGER 1
+//~ #undef USE_DATALOGGER_TRIGGER
+#endif
+#if USE_DATALOGGER_TRIGGER // support Datalog trigger
+typedef enum Datalogger_Trigger_enum_t {
+    trigger_Halt = 0,               //!< halt
+    trigger_FreeRun = 1,            //!< free run as fast as possible
+    trigger_Timer = 2,              //!< timer (configure interval)
+    trigger_PlatformDigitalInput,   //!< platform digital input (configure digital input pin reference)
+    trigger_SPIDeviceRegRead,       //!< SPI device register read (configure regaddr, mask value, match value)
+} Datalogger_Trigger_enum_t;
+Datalogger_Trigger_enum_t Datalogger_Trigger = trigger_FreeRun;
+#endif // USE_DATALOGGER_TRIGGER support Datalog trigger
+
+//--------------------------------------------------
+// print column header banner for csv data columns
+void Datalogger_PrintHeader();
+
+//--------------------------------------------------
 // Option to validate SPI link by reading PART_ID register
 #ifndef VERIFY_PART_ID_IN_LOOP
 #if defined(SPI_ADC_DeviceName) // SPI connected ADC
@@ -1591,6 +1625,7 @@
 #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
+// MAX11410 specific per-channel config register v_filter
 uint8_t SPI_AIN_Cfg_v_filter_ch[NUM_DUT_ANALOG_IN_CHANNELS] = {
     0x34, // AIN0 @ v_filter=0x34
     0x34, // AIN1 @ v_filter=0x34
@@ -1604,6 +1639,7 @@
     0x34, // AIN9 @ v_filter=0x34
 };
 //
+// MAX11410 specific per-channel config register v_ctrl
 uint8_t SPI_AIN_Cfg_v_ctrl_ch[NUM_DUT_ANALOG_IN_CHANNELS] = {
     0x42, // AIN0 @ v_ctrl=0x42
     0x42, // AIN1 @ v_ctrl=0x42
@@ -1617,6 +1653,7 @@
     0x42, // AIN9 @ v_ctrl=0x42
 };
 //
+// MAX11410 specific per-channel config register v_pga
 uint8_t SPI_AIN_Cfg_v_pga_ch[NUM_DUT_ANALOG_IN_CHANNELS] = {
     0x00, // AIN0 @ v_pga=0x00
     0x00, // AIN1 @ v_pga=0x00
@@ -1769,6 +1806,399 @@
 #endif
 #endif // defined(LOG_PLATFORM_AIN)
 
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+//--------------------------------------------------
+inline void print_command_prompt()
+{
+    //~ Serial.println(F(">"));
+    cmdLine.serial().printf("\r\n> ");
+}
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+//--------------------------------------------------
+void main_menu_status(CmdLine & cmdLine)
+{
+    cmdLine.serial().printf("\r\nMain menu");
+#if APPLICATION_MAX5715 // main_menu_status banner
+    cmdLine.serial().printf(" MAX5715 12-bit 4-ch SPI VOUT DAC");
+#elif APPLICATION_MAX11131 // main_menu_status banner
+    cmdLine.serial().printf(" MAX11131 12-bit 3MSps 16-ch ADC");
+#elif APPLICATION_MAX5171 // main_menu_status banner
+    cmdLine.serial().printf(" MAX5171 14-bit Force/Sense VOUT DAC");
+#elif APPLICATION_MAX11410 // main_menu_status banner
+    cmdLine.serial().printf(" MAX11410 24-bit 1.9ksps Delta-Sigma ADC");
+#elif APPLICATION_MAX12345 // main_menu_status banner
+    cmdLine.serial().printf(" MAX12345");
+#else
+    //cmdLine.serial().printf(" ");
+#endif
+    //cmdLine.serial().printf(" %s", TARGET_NAME);
+    if (cmdLine.nameStr())
+    {
+        cmdLine.serial().printf(" [%s]", cmdLine.nameStr());
+    }
+#if HAS_BUTTON1_DEMO_INTERRUPT
+    cmdLine.serial().printf(" [Button1=DemoConfig1]");
+#endif
+#if HAS_BUTTON2_DEMO_INTERRUPT
+    cmdLine.serial().printf(" [Button2=DemoConfig2]");
+#endif
+#if HAS_BUTTON1_DEMO
+    // print BUTTON1 status
+    cmdLine.serial().printf("\r\n BUTTON1 = %d", button1.read());
+#endif
+#if HAS_BUTTON2_DEMO
+    // print BUTTON1 status
+    cmdLine.serial().printf("\r\n BUTTON2 = %d", button2.read());
+#endif
+    cmdLine.serial().printf("\r\n ? -- help");
+}
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+//--------------------------------------------------
+void main_menu_help(CmdLine & cmdLine)
+{
+    // ? -- help
+    //~ cmdLine.serial().printf("\r\nMenu:");
+    cmdLine.serial().printf("\r\n # -- lines beginning with # are comments");
+#if USE_SELFTEST
+    cmdLine.serial().printf("\r\n . -- SelfTest");
+#endif // USE_SELFTEST
+#if USE_DATALOGGER_TRIGGER // support Datalog trigger
+    // TODO Datalog trigger menu
+    // set Datalogger_Trigger to trigger_Halt or trigger_FreeRun
+    // Datalogger_Trigger = trigger_Halt // halt the datalogger; continue accepting commands
+    // Datalogger_Trigger = trigger_FreeRun // free run as fast as possible
+    cmdLine.serial().printf("\r\n LR -- Datalog free run as fast as possible");
+#endif // USE_DATALOGGER_TRIGGER support Datalog trigger
+    //cmdLine.serial().print(F("\r\n ! -- Initial Configuration"));
+    //
+    // % 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
+    // %I... -- I2C diagnostics
+    // %IP -- I2C probe
+    // %IC scl=100khz ADDR=? -- I2C configure
+    // %IW ADDR=? cmd=? data,data,data -- 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
+    //
+#if HAS_digitalInOuts
+    // %Hpin -- digital output high
+    // %Lpin -- digital output low
+    // %?pin -- digital input
+    cmdLine.serial().printf("\r\n %%Hn {pin:");
+    list_digitalInOutPins(cmdLine.serial());
+    cmdLine.serial().printf("} -- High Output");
+    cmdLine.serial().printf("\r\n %%Ln {pin:");
+    list_digitalInOutPins(cmdLine.serial());
+    cmdLine.serial().printf("} -- Low Output");
+    cmdLine.serial().printf("\r\n %%?n {pin:");
+    list_digitalInOutPins(cmdLine.serial());
+    cmdLine.serial().printf("} -- Input");
+#endif
+
+#if HAS_analogIns
+    // Menu A) analogRead A0..7
+    // %A %Apin -- analog input
+    // analogRead(pinIndex) // analog input pins A0, A1, A2, A3, A4, A5; float voltage = analogRead(A0) * (5.0 / 1023.0)
+    cmdLine.serial().printf("\r\n %%A -- analogRead");
+#endif
+
+#if HAS_SPI2_MAX541
+    // TODO1: MAX541 max541(spi2_max541, spi2_max541_cs);
+    cmdLine.serial().printf("\r\n %%D -- DAC output MAX541 (SPI2)");
+#endif
+
+#if HAS_I2C // SUPPORT_I2C
+    // TODO: support I2C HAS_I2C // SUPPORT_I2C
+    // VERIFY: I2C utility commands SUPPORT_I2C
+    // VERIFY: report g_I2C_SCL_Hz = (F_CPU / ((TWBR * 2) + 16)) from last Wire_Sr.setClock(I2C_SCL_Hz);
+    // %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
+    //g_I2C_SCL_Hz = (F_CPU / ((TWBR * 2) + 16));   // 'F_CPU' 'TWBR' not declared in this scope
+    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.));
+    cmdLine.serial().printf("\r\n %%IW byte byte ... byte RD=? ADDR=0x%2.2x -- I2C write/read",
+                            g_I2C_deviceAddress7);
+    //
+#if SUPPORT_I2C
+    // Menu ^ cmd=?) i2c_smbus_read_word_data
+    cmdLine.serial().printf("\r\n %%I^ cmd=? -- i2c_smbus_read_word_data");
+    // test low-level I2C i2c_smbus_read_word_data
+#endif // SUPPORT_I2C
+    //cmdLine.serial().printf(" H) Hunt for attached I2C devices");
+    cmdLine.serial().printf("\r\n %%IP -- I2C Probe for attached devices");
+    // cmdLine.serial().printf(" s) search i2c address");
+#endif // SUPPORT_I2C
+
+#if HAS_SPI // SUPPORT_SPI
+    // TODO: support SPI HAS_SPI // SUPPORT_SPI
+    // SPI test command  S (mosiData)+
+    // %S... -- SPI diagnostics
+    // %SC sclk=1Mhz -- SPI configure
+    // %SW -- write (write and read)
+    // %SR -- read (alias for %SW because SPI always write and read)
+    // spi.format(8,0); // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=0 rising edge (initial default)
+    // spi.format(8,1); // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=1 falling edge (initial default)
+    // spi.format(8,2); // int bits_must_be_8, int mode=0_3 CPOL=1,CPHA=0 falling edge (initial default)
+    // spi.format(8,3); // int bits_must_be_8, int mode=0_3 CPOL=1,CPHA=1 rising edge (initial default)
+    // spi.frequency(1000000); // int SCLK_Hz=1000000 = 1MHz (initial default)
+    // mode | POL PHA
+    // -----+--------
+    //   0  |  0   0
+    //   1  |  0   1
+    //   2  |  1   0
+    //   3  |  1   1
+    //cmdLine.serial().printf(" S) SPI mosi,mosi,...mosi hex bytes SCLK=1000000 CPOL=0 CPHA=0");
+    // fixed: mbed-os-5.11: [Warning] format '%d' expects argument of type 'int', but argument 3 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
+    cmdLine.serial().printf("\r\n %%SC SCLK=%ld=%1.3fMHz CPOL=%d CPHA=%d -- SPI config",
+                            g_SPI_SCLK_Hz, (g_SPI_SCLK_Hz / 1000000.),
+                            ((g_SPI_dataMode & SPI_MODE2) ? 1 : 0),
+                            ((g_SPI_dataMode & SPI_MODE1) ? 1 : 0));
+    cmdLine.serial().printf("\r\n %%SD -- SPI diagnostic messages ");
+    if (g_MAX11410_device.onSPIprint) {
+        cmdLine.serial().printf("hide");
+    }
+    else {
+        cmdLine.serial().printf("show");
+    }
+    cmdLine.serial().printf("\r\n %%SW mosi,mosi,...mosi -- SPI write hex bytes");
+    // VERIFY: parse new SPI settings parse_strCommandArgs() SCLK=1000000 CPOL=0 CPHA=0
+#endif // SUPPORT_SPI
+       //
+       // Application-specific commands (help text) here
+       //
+#if APPLICATION_ArduinoPinsMonitor
+    cmdLine.serial().printf("\r\n A-Z,a-z,0-9 -- reserved for application use");     // ArduinoPinsMonitor
+#endif // APPLICATION_ArduinoPinsMonitor
+       //
+
+    //~ extern void MAX11410_menu_help(CmdLine & cmdLine); // defined in Test_Menu_MAX11410.cpp\n
+    //~ MAX11410_menu_help(cmdLine);
+}
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+//--------------------------------------------------
+void main_menu_onEOLcommandParser(CmdLine& cmdLine)
+{
+    // TODO: process command line
+    cmdLine.serial().printf("\r\nCmdLine buf:");
+    cmdLine.serial().printf("%s\r\n", cmdLine.str());
+
+#if USE_DATALOGGER_TRIGGER // support Datalog trigger
+    // If datalog is free running, halt on any possible received command
+    if (Datalogger_Trigger == trigger_FreeRun) {
+        Datalogger_Trigger = trigger_Halt;
+    }
+#endif // USE_DATALOGGER_TRIGGER support Datalog trigger
+
+    // 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 USE_SELFTEST
+        case '.':
+        {
+            // . -- SelfTest
+            cmdLine.serial().printf("SelfTest()");
+            SelfTest(cmdLine);
+        }
+        break;
+#endif // USE_SELFTEST
+#if 0 // APPLICATION_ArduinoPinsMonitor
+        case '%':
+        {
+            pinsMonitor_submenu_onEOLcommandParser(cmdLine);
+        }
+        break;         // case '%'
+#endif // APPLICATION_ArduinoPinsMonitor
+#if USE_DATALOGGER_TRIGGER // support Datalog trigger
+        // TODO Datalog trigger menu
+        // set Datalogger_Trigger to trigger_Halt or trigger_FreeRun
+        // Datalogger_Trigger = trigger_Halt // halt the datalogger; continue accepting commands
+        // Datalogger_Trigger = trigger_FreeRun // free run as fast as possible
+        case 'L':
+        {
+            // halt the datalogger; continue accepting commands
+            Datalogger_Trigger = trigger_Halt;
+            switch (cmdLine[1])
+            {
+                case 'R': case 'r':
+                    // free run as fast as possible
+                    Datalogger_Trigger = trigger_FreeRun; 
+                    Datalogger_PrintHeader();
+                    return; // instead of break; avoid falling through to print_command_prompt();
+            }
+        }
+        break;         // case 'L'
+#endif // USE_DATALOGGER_TRIGGER support Datalog trigger
+       //
+       // 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:
+#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 ");
+                //~ 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().print("\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
+    print_command_prompt();
+}
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+//--------------------------------------------------
+// print column header banner for csv data columns
+void Datalogger_PrintHeader()
+{
+    // 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) {
+                continue;
+            }
+            // comma between fields
+            if (field_index > 0) {
+                cmdLine.serial().printf(",");
+            }
+            // AIN_index column header prefix
+#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) {
+                cmdLine.serial().printf("\"AIN%d-%d_BIP", channel_index, channel_index+1);
+            }
+            else {
+                cmdLine.serial().printf("\"AIN%d", channel_index);
+            }
+#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
+                // _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) {
+                // _V column header suffix
+                cmdLine.serial().printf("_V\"");
+# if HAS_DAPLINK_SERIAL
+                cmdLine_DAPLINKserial.serial().printf("_V\"");
+# endif // HAS_DAPLINK_SERIAL
+            }
+        }
+
+#if VERIFY_PART_ID_IN_LOOP
+        // PART_ID field: Device ID Validation
+        cmdLine.serial().printf(",\"PART_ID\"");
+# if HAS_DAPLINK_SERIAL
+        cmdLine_DAPLINKserial.serial().printf(",\"PART_ID\"");
+# endif // HAS_DAPLINK_SERIAL
+#endif // VERIFY_PART_ID_IN_LOOP
+#endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
+#if defined(LOG_PLATFORM_AIN) // Datalog Arduino platform analog inputs
+        for (int channel_index = 0; channel_index < NUM_PLATFORM_ANALOG_IN_CHANNELS; field_index++, channel_index++) {
+            // comma between fields
+            if (field_index > 0) {
+                cmdLine.serial().printf(",");
+            }
+            // AIN_index column header prefix
+            cmdLine.serial().printf("\"A%d", channel_index);
+#if LOG_PLATFORM_ANALOG_IN_LSB
+            // _LSB column header suffix
+            cmdLine.serial().printf("_LSB\"");
+#elif LOG_PLATFORM_ANALOG_IN_VOLTS
+            // _V column header suffix
+            cmdLine.serial().printf("_V\"");
+#endif
+        }
+#endif // defined(LOG_PLATFORM_AIN)
+        // end of column header line
+        cmdLine.serial().printf("\r\n");
+# if HAS_DAPLINK_SERIAL
+        cmdLine_DAPLINKserial.serial().printf("\r\n");
+# endif // HAS_DAPLINK_SERIAL
+} // void Datalogger_PrintHeader()
+
 // CODE GENERATOR: example code for ADC: serial port declaration
 //--------------------------------------------------
 // Declare the Serial driver
@@ -1860,6 +2290,26 @@
 int main()
 {
     // setup: put your setup code here, to run once
+#if USE_CMDLINE_MENUS // support CmdLine command menus
+    // Configure serial ports
+    cmdLine.clear();
+    //~ cmdLine.serial().printf("\r\n cmdLine.serial().printf test\r\n");
+    cmdLine.onEOLcommandParser = main_menu_onEOLcommandParser;
+    //~ cmdLine.diagnostic_led_EOF = diagnostic_led_EOF;
+    /// CmdLine::set_immediate_handler(char, functionPointer_void_void_on_immediate_0x21);
+    //~ cmdLine.on_immediate_0x21 = on_immediate_0x21;
+    //~ cmdLine.on_immediate_0x7b = on_immediate_0x7b;
+    //~ cmdLine.on_immediate_0x7d = on_immediate_0x7d;
+# if HAS_DAPLINK_SERIAL
+    cmdLine_DAPLINKserial.clear();
+    //~ cmdLine_DAPLINKserial.serial().printf("\r\n cmdLine_DAPLINKserial.serial().printf test\r\n");
+    cmdLine_DAPLINKserial.onEOLcommandParser = main_menu_onEOLcommandParser;
+    /// @todo CmdLine::set_immediate_handler(char, functionPointer_void_void_on_immediate_0x21);
+    //~ cmdLine_DAPLINKserial.on_immediate_0x21 = on_immediate_0x21;
+    //~ cmdLine_DAPLINKserial.on_immediate_0x7b = on_immediate_0x7b;
+    //~ cmdLine_DAPLINKserial.on_immediate_0x7d = on_immediate_0x7d;
+# endif
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
 
     // example code: serial port banner message
     wait(3); // 3000ms timing delay function, platform-specific
@@ -1920,81 +2370,40 @@
 #endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
 
         // column header banner for csv data columns
-        //~ cmdLine.serial().printf("\"AIN0_V\",\"AIN1_V\",\"AIN2_V\",\"AIN3_V\",\"AIN4_V\",\"AIN5_V\",\"AIN6_V\",\"AIN7_V\",\"AIN8_V\",\"AIN9_V\"");
-        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) {
+        Datalogger_PrintHeader();
+
+        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 (serial.readable()) {
+                int c = serial.getc(); // instead of getc() or fgetc()
+                cmdLine.append(c);
+                // cmdLine.onEOLcommandParser handler implements menus
+            } // if (Serial.available())
+#endif // USE_CMDLINE_MENUS support CmdLine command menus
+
+#if USE_DATALOGGER_TRIGGER // support Datalog trigger
+            // TODO Datalog trigger
+            if (Datalogger_Trigger == trigger_Halt) {
+                // halt the datalogger; continue accepting commands
                 continue;
             }
-            // comma between fields
-            if (field_index > 0) {
-                cmdLine.serial().printf(",");
-            }
-            // AIN_index column header prefix
-#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) {
-                cmdLine.serial().printf("\"AIN%d-%d_BIP", channel_index, channel_index+1);
-            }
-            else {
-                cmdLine.serial().printf("\"AIN%d", channel_index);
+            if (Datalogger_Trigger == trigger_FreeRun) {
+                // free run as fast as possible
             }
-#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
-                // _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) {
-                // _V column header suffix
-                cmdLine.serial().printf("_V\"");
-# if HAS_DAPLINK_SERIAL
-                cmdLine_DAPLINKserial.serial().printf("_V\"");
-# endif // HAS_DAPLINK_SERIAL
+            if (Datalogger_Trigger == trigger_Timer) {
+                // timer (configure interval)
             }
-        }
-
-#if VERIFY_PART_ID_IN_LOOP
-        // PART_ID field: Device ID Validation
-        cmdLine.serial().printf(",\"PART_ID\"");
-# if HAS_DAPLINK_SERIAL
-        cmdLine_DAPLINKserial.serial().printf(",\"PART_ID\"");
-# endif // HAS_DAPLINK_SERIAL
-#endif // VERIFY_PART_ID_IN_LOOP
-#endif // defined(SPI_ADC_DeviceName) // SPI connected ADC
-#if defined(LOG_PLATFORM_AIN) // Datalog Arduino platform analog inputs
-        for (int channel_index = 0; channel_index < NUM_PLATFORM_ANALOG_IN_CHANNELS; field_index++, channel_index++) {
-            // comma between fields
-            if (field_index > 0) {
-                cmdLine.serial().printf(",");
+            if (Datalogger_Trigger == trigger_PlatformDigitalInput) {
+                // platform digital input (configure digital input pin reference)
             }
-            // AIN_index column header prefix
-            cmdLine.serial().printf("\"A%d", channel_index);
-#if LOG_PLATFORM_ANALOG_IN_LSB
-            // _LSB column header suffix
-            cmdLine.serial().printf("_LSB\"");
-#elif LOG_PLATFORM_ANALOG_IN_VOLTS
-            // _V column header suffix
-            cmdLine.serial().printf("_V\"");
-#endif
-        }
-#endif // defined(LOG_PLATFORM_AIN)
-        // end of column header line
-        cmdLine.serial().printf("\r\n");
-# if HAS_DAPLINK_SERIAL
-        cmdLine_DAPLINKserial.serial().printf("\r\n");
-# endif // HAS_DAPLINK_SERIAL
+            if (Datalogger_Trigger == trigger_SPIDeviceRegRead) {
+                // SPI device register read (configure regaddr, mask value, match value)
+            }
+#endif // USE_DATALOGGER_TRIGGER support Datalog trigger
 
-        while(1) { // this code repeats forever
-            // this code repeats forever
             // CODE GENERATOR: example code: has no member function ScanStandardExternalClock
             // CODE GENERATOR: example code: has no member function ReadAINcode
             // CODE GENERATOR: example code: member function Read_All_Voltages
@@ -2042,7 +2451,7 @@
             // wait(3.0);
             // CODE GENERATOR: print conversion result
             // Use Arduino Serial Plotter to view output: Tools | Serial Plotter
-            field_index = 0;
+            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) {