Erick / Mbed 2 deprecated ICE-F412

Dependencies:   mbed-rtos mbed

ICE-Application/src/CommandParser/cmd.cpp

Committer:
jmarkel44
Date:
2017-01-24
Revision:
0:61364762ee0e

File content as of revision 0:61364762ee0e:

/*
 * ===============================================================
 *  Natural Tiny Shell (NT-Shell) Application example.
 *  Version 0.0.6
 * ===============================================================
 * Copyright (c) 2010-2011 Shinichiro Nakamura
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * ===============================================================
 */

#include <mbed.h>
#include <mbed_stats.h>
#include <stdlib.h>
#include <vector>
#include <rtos.h>
#include "cmd.h"
#include "ntshell.h"
#include "ntopt.h"
#include "cJSON.h"
#include "v7.h"
#include "global.h"
#include "OutputTask.h"
#include "ModbusMasterApi.h"
#include "ConfigurationHandler.h"
#include "mfs.h"
#include "rtc.h"
#include "ConfigFs.h"
#include "version.h"
#include "ICELog.h"
#include "utilities.h"

ntshell_t ntshell;
extern Serial console;

// the readers and writers
int func_read(char *buf, int cnt);
int func_write(const char *buf, int cnt);
int func_cb_ntshell(const char *text);
void func_cb_ntopt(int argc, char **argv);

// the command table element
typedef struct {
    char *command;                              // command (from shell)
    char *description;                          // descrption
    void (*func)(int argc, char **argv);        // callback function
} command_table_t;

const command_table_t cmdlist[] = {
    {"?",                   "help command",                                     cmd_help            },
    {"cif",                 "create an input file",                             cmd_cif             },
    {"cof",                 "create an output file",                            cmd_cof             },
    {"create-ca",           "create a control algorithm file",                  cmd_createCAlg      },
    {"create-fs",           "create a failsafe control",                        cmd_createFailsafe  },
    {"create-mn",           "create a manual control",                          cmd_createManual    },
    {"create-se",           "create a sensor error control",                    cmd_createSError    },
    {"create-seq",          "create a sequence control",                        cmd_createSequence  },
    {"create-sp",           "create a setpoint control",                        cmd_createSetpoint  },
    {"create-tm",           "create a timer control",                           cmd_createTimer     },
    {"create-vreg",         "create a virtual register",                        cmd_createVreg      },
    {"debug-fs",            "debug failsafe controls",                          cmd_debug_fs        },
    {"debug-mn",            "debug manual controls",                            cmd_debug_mn        },
    {"debug-se",            "debug sensor error controls",                      cmd_debug_se        },
    {"debug-seq",           "debug sequence controls",                          cmd_debug_seq       },
    {"debug-sp",            "debug setpoint controls",                          cmd_debug_sp        },
    {"debug-tm",            "debug timer controls",                             cmd_debug_tm        },
    {"delete-file",         "delete a file from EEPROM",                        cmd_deleteFile      },
    {"destroy-control",     "destroy a control",                                cmd_destroy         },
    {"format-fs",           "format EEPROM file system",                        cmd_formatFS        },
    {"heap-stats",          "dump heap data",                                   cmd_heap_stats      },
    {"help",                "help command",                                     cmd_help            },
    {"json-test",           "JSON parser test",                                 cmd_json            },
    {"log-level",           "set debug log-level",                              cmd_logLevel        },
    {"ls",                  "list files in EEPROM",                             cmd_lsFile          },
    {"modmap",              "dump modbus register map",                         cmd_modmap          },
    {"preload",             "pre-load phase-1 demo files",                      cmd_preload         },
    {"read-file",           "read file from EEPROM",                            cmd_readFile        },
    {"reset",               "software reset",                                   cmd_reset           },
    {"simall",              "simulate multiple inputs",                         cmd_simall          },
    {"simerr",              "simulate input error",                             cmd_simerr          },
    {"simin",               "simulate input",                                   cmd_simin           },
    {"show-ca",             "show control algorithms",                          cmd_ShowAlgorithms  },
    {"show-controls",       "show active controls",                             cmd_ShowControls    },
    {"show-tm-controls",    "display active timer controls",                    cmd_ShowTimers      },
    {"show-mn-controls",    "display active manual controls",                   cmd_ShowManuals     },
    {"show-co-controls",    "display active composite controls",                cmd_ShowComposites  },
    {"show-fs-controls",    "display active failsafe controls",                 cmd_ShowFailsafes   },
    {"show-se-controls",    "display active sensor error controls",             cmd_ShowSensorErrors},
    {"show-seq-controls",   "display active sequential controls",               cmd_ShowSequences   },
    {"show-sp-controls",    "display active setpoint controls",                 cmd_ShowSetpoints   },
    {"show-outputs",        "display the output hierarchy",                     cmd_outputs         },
    //{"spi-test",            "test SPI FLASH interface",                         cmd_spiTest         },
    {"stack-stats",         "dump stack stats",                                 cmd_stack           },
    {"test-log-level",      "tests the log functions",                          cmd_testLog         },
    {"test-prebleed",       "test the pre-bleed scripts",                       cmd_testPreBleed    },
    {"v7-test",             "V7 test",                                          cmd_v7,             },
    {"version",             "display version info",                             cmd_version         },
    {"vregmap",             "display the virtual register map",                 cmd_vregmap         },
    {"write-file",          "write a file to EEPROM",                           cmd_writeFile       },
    {"get-time",            "get time from RTC",                                cmd_getTime         },
    {"set-time",            "set time from RTC",                                cmd_setTime         },
    {NULL, NULL, NULL}
};


void cmd_testLog(int argc, char **argv)
{
    logFatal    ("Testing");
    logError    ("Testing");
    logWarning  ("Testing");
    logInfo     ("Testing");
    logDebug    ("Testing");
    logTrace    ("Testing");

}

//
// function:            cmd_debug_fs
// decription:          debug failsafe controls (ON|OFF)
//
void cmd_debug_fs(int argc, char **argv)
{
    extern bool debugFailsafeControl;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugFailsafeControl);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage: debug-fs <1|0>\n");
        printf("\rexample: debug-fs 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugFailsafeControl = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugFailsafeControl = false;
    } else {
        goto usage;
    }
}

//
// function:            cmd__debug_man
// description:         debug manual controls (ON|OFF)
//
void cmd_debug_mn(int argc, char **argv)
{
    extern bool debugManualControl;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugManualControl);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage:    debug-man <1|0>\n");
        printf("\rexample:  debug-man 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugManualControl = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugManualControl = false;
    } else {
        goto usage;
    }
}

//
// function:            cmd_debug_se
// description:         debug sensor error controls (ON|OFF)
//
void cmd_debug_se(int argc, char **argv)
{
    extern bool debugSensorError;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugSensorError);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage:   debug-se <1|0>\n");
        printf("\rexample: debug-se 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugSensorError = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugSensorError = false;
    } else {
        goto usage;
    }
}

//
// function:            cmd_debug_seq
// description:         debug sequence controls (ON|OFF
//
void cmd_debug_seq(int argc, char **argv)
{
    extern bool debugSequenceControl;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugSequenceControl);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage:   debug-seq <1|0>\n");
        printf("\rexample: debug-seq 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugSequenceControl = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugSequenceControl = false;
    } else {
        goto usage;
    }
}

//
// function:            cmd_debug_sp
// description:         debug setpoint controls
//
void cmd_debug_sp(int argc, char **argv)
{
    extern bool debugSetpointControl;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugSetpointControl);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage:   debug-sp <1|0>\n");
        printf("\rexample: debug-sp 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugSetpointControl = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugSetpointControl = false;
    } else {
        goto usage;
    }
}

//
// function:            cmd_debug_tm
// description:         debug timer controls (ON|OFF)
//
void cmd_debug_tm(int argc, char **argv)
{
    extern bool debugTimerControl;

    if ( argc == 1 ) {
        printf("\rCurrent level is %d\r\n", debugTimerControl);
        return;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage:   debug-tm <1|0>\n");
        printf("\rexample: debug-tm 1\n");
        return;
    }

    if ( (atoi(argv[1])) == 1 ) {
        debugTimerControl = true;
    } else if ( (atoi(argv[1])) == 0  ) {
        debugTimerControl = false;
    } else {
        goto usage;
    }
}


void cmd_heap_stats(int argc, char **argv)
{
#ifndef __ICCARM__
    UNUSED(argc), UNUSED(argv);
    printf("\r%s\r\n", Util_getHeapData().c_str());
#if 0
    UNUSED(argc);
    UNUSED(argv);

    mbed_stats_heap_t s;
    mbed_stats_heap_get(&s);

    printf("\rHeap statistics:\n");
    printf("\r    bytes allocated......%u\n", s.current_size/1024);
    printf("\r    max bytes allocated..%u\n", s.max_size/1024);
    printf("\r    cumulative sum.......%u\n", s.total_size);
    printf("\r    reserved size........%u\n", s.reserved_size);
    printf("\r    allocations..........%u\n", s.alloc_cnt);
    printf("\r    failed allocations...%u\n", s.alloc_fail_cnt);

    return;
#endif
#endif
}

void cmd_ShowAlgorithms(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    ConfigurationHandler_showAlgorithms();
    printf("\r\n");
}

void cmd_ShowControls(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    ConfigurationHandler_showControls();
    printf("\r\n");

}

void cmd_reset(int argc, char **argv)
{
    NVIC_SystemReset();
}

void cmd_ShowTimers(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showTimerControls();
    printf("\r\n");
}

void cmd_ShowManuals(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showManualControls();
    printf("\r\n");
}

void cmd_ShowFailsafes(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showFailsafeControls();
    printf("\r\n");
}

void cmd_ShowSequences(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showSequenceControls();
}

void cmd_ShowComposites(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showCompositeControls();
    printf("\r\n");
}

void cmd_ShowSetpoints(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showSetpointControls();
    printf("\r\n");
}

void cmd_ShowSensorErrors(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    ConfigurationHandler_showSensorErrorControls();
    printf("\r\n");
}


/*****************************************************************************
 * Function:        cmd_simerr
 * Description:     simulate an input error
 *
 * @return          none
 *****************************************************************************/
void cmd_simerr(int argc, char **argv)
{
    if ( argc < 3 ) {
        printf("\rusage:   simerr <input> <errflag_value>\n");
        printf("\rexample: simerr i_bdcond01 9\n");
        return;
    }

    ModbusRegisterMap[argv[1]].simulated = true;
    SimulateInputMap[argv[1]].errflag = (uint32_t)(atoi(argv[2]));
}

/*****************************************************************************
 * Function:        cmd_simin
 * Description:     simulat input
 *
 * @param           argc-> number of args
 * @param           argv-> input
 * @return          none
 *****************************************************************************/
void cmd_simin(int argc, char **argv)
{
    if ( argc != 3 && argc != 7 ) {
        printf("\rusage: simin <input> <value> <<low> <hi> <up_step> <down_step>>\r\n");
        printf("\rexample: simin i_tra01 100 94 106 1 .25\r\n");
        printf("\rexample: simin i_bdcond01 2000 1990 2006 .25 1\r\n");
        printf("\rexample: simin i_bdcond01 1800\n");
        return;
    }

    //float value = atof( argv[2] );
    SimulateInputMap[argv[1]].start_value = atof(argv[2]);

    ModbusRegisterMap[argv[1]].simulated = true;

    if ( argc == 3 ) {
        SimulateInputMap[argv[1]].min = 0;
        SimulateInputMap[argv[1]].max = 0;
        SimulateInputMap[argv[1]].moving_up = false;
        return;
    }
    SimulateInputMap[argv[1]].min = atof(argv[3]);
    SimulateInputMap[argv[1]].max = atof(argv[4]);
    SimulateInputMap[argv[1]].up_step = atof(argv[5]);
    SimulateInputMap[argv[1]].down_step = atof(argv[6]);
    SimulateInputMap[argv[1]].moving_up = true;

}

/*****************************************************************************
 * Function:        cmd_simall
 * Description:     simulat multiple inputs
 *
 * @return          none
 *****************************************************************************/
void cmd_simall(int argc, char **argv)
{

    if ( argc > 1 ) {

        printf("\r  setting: simin i_tra01 100\n");
        ModbusRegisterMap["i_tra01"].simulated = true;
        SimulateInputMap["i_tra01"].start_value = 130;
        SimulateInputMap["i_tra01"].min = 0;
        SimulateInputMap["i_tra01"].max = 0;
        SimulateInputMap["i_tra01"].up_step = 0;
        SimulateInputMap["i_tra01"].down_step = 0;
        SimulateInputMap["i_tra01"].moving_up = true;

        printf("\r  setting: i_tag01 100\n");
        ModbusRegisterMap["i_tag01"].simulated = true;
        SimulateInputMap["i_tag01"].start_value = 100;
        SimulateInputMap["i_tag01"].min = 0;
        SimulateInputMap["i_tag01"].max = 0;
        SimulateInputMap["i_tag01"].up_step = 0;
        SimulateInputMap["i_tag01"].down_step = 0;
        SimulateInputMap["i_tag01"].moving_up = true;

        printf("\r  setting: i_bdcond01 1800\n");
        ModbusRegisterMap["i_bdcond01"].simulated = true;
        SimulateInputMap["i_bdcond01"].start_value = 1800;
        SimulateInputMap["i_bdcond01"].min = 0;
        SimulateInputMap["i_bdcond01"].max = 0;
        SimulateInputMap["i_bdcond01"].up_step = 0;
        SimulateInputMap["i_bdcond01"].down_step = 0;
        SimulateInputMap["i_bdcond01"].moving_up = true;

        printf("\r  setting: i_cond_temp01 25\n");
        ModbusRegisterMap["i_cond_temp01"].simulated = true;
        SimulateInputMap["i_cond_temp01"].start_value = 25000.0;
        SimulateInputMap["i_cond_temp01"].min = 0;
        SimulateInputMap["i_cond_temp01"].max = 0;
        SimulateInputMap["i_cond_temp01"].up_step = 0;
        SimulateInputMap["i_cond_temp01"].down_step = 0;
        SimulateInputMap["i_cond_temp01"].moving_up = true;

        printf("\r  setting: i_ph01 8\n");
        ModbusRegisterMap["i_ph01"].simulated = true;
        SimulateInputMap["i_ph01"].start_value = 8000;
        SimulateInputMap["i_ph01"].min = 0;
        SimulateInputMap["i_ph01"].max = 0;
        SimulateInputMap["i_ph01"].up_step = 0;
        SimulateInputMap["i_ph01"].down_step = 0;
        SimulateInputMap["i_ph01"].moving_up = true;

        printf("\r  setting: i_ph_temp01 25\n");
        ModbusRegisterMap["i_ph_temp01"].simulated = true;
        SimulateInputMap["i_ph_temp01"].start_value = 25000.0;
        SimulateInputMap["i_ph_temp01"].min = 0;
        SimulateInputMap["i_ph_temp01"].max = 0;
        SimulateInputMap["i_ph_temp01"].up_step = 0;
        SimulateInputMap["i_ph_temp01"].down_step = 0;
        SimulateInputMap["i_ph_temp01"].moving_up = true;

        printf("\r  setting: i_orp01 350\n");
        ModbusRegisterMap["i_orp01"].simulated = true;
        SimulateInputMap["i_orp01"].start_value = 350;
        SimulateInputMap["i_orp01"].min = 0;
        SimulateInputMap["i_orp01"].max = 0;
        SimulateInputMap["i_orp01"].up_step = 0;
        SimulateInputMap["i_orp01"].down_step = 0;
        SimulateInputMap["i_orp01"].moving_up = true;


        printf("\r  setting: i_flowsw01 1\n");
        ModbusRegisterMap["i_flowsw01"].simulated = true;
        SimulateInputMap["i_flowsw01"].start_value = 1;
        SimulateInputMap["i_flowsw01"].min = 0;
        SimulateInputMap["i_flowsw01"].max = 0;
        SimulateInputMap["i_flowsw01"].up_step = 0;
        SimulateInputMap["i_flowsw01"].down_step = 0;
        SimulateInputMap["i_flowsw01"].moving_up = true;

        return;
    }

    printf("\rsetting: simin i_tra01 130 120 140 1 .25\r\n");
    printf("\rsetting: simin i_tag01 100 90 110 1 .25\r\n");
    printf("\rsetting: simin i_bdcond01 1800 1725 1875 1 5\r\n");
    printf("\rsetting: simin i_ph01 8.0 7.25 8.75 .0. .1\r\n");
    printf("\rsetting: simin i_orp01 350 300 400 5 1\r\n");

    ModbusRegisterMap["i_tra01"].simulated = true;
    SimulateInputMap["i_tra01"].start_value = 130;
    SimulateInputMap["i_tra01"].min = 120;
    SimulateInputMap["i_tra01"].max = 140;
    SimulateInputMap["i_tra01"].up_step = 1;
    SimulateInputMap["i_tra01"].down_step = .25;

    ModbusRegisterMap["i_tag01"].simulated = true;
    SimulateInputMap["i_tag01"].start_value = 100;
    SimulateInputMap["i_tag01"].min = 90;
    SimulateInputMap["i_tag01"].max = 110;
    SimulateInputMap["i_tag01"].up_step = 1;
    SimulateInputMap["i_tag01"].down_step = .25;

    ModbusRegisterMap["i_bdcond01"].simulated = true;
    SimulateInputMap["i_bdcond01"].start_value = 1800;
    SimulateInputMap["i_bdcond01"].min = 1725;
    SimulateInputMap["i_bdcond01"].max = 1875;
    SimulateInputMap["i_bdcond01"].up_step = 1;
    SimulateInputMap["i_bdcond01"].down_step = 5;

    ModbusRegisterMap["i_ph01"].simulated = true;
    SimulateInputMap["i_ph01"].start_value = 8000;
    SimulateInputMap["i_ph01"].min = 7250;
    SimulateInputMap["i_ph01"].max = 8750;
    SimulateInputMap["i_ph01"].up_step = 5;
    SimulateInputMap["i_ph01"].down_step = 10;

    ModbusRegisterMap["i_orp01"].simulated = true;
    SimulateInputMap["i_orp01"].start_value = 350;
    SimulateInputMap["i_orp01"].min = 300;
    SimulateInputMap["i_orp01"].max = 400;
    SimulateInputMap["i_orp01"].up_step = 5;
    SimulateInputMap["i_orp01"].down_step = 1;

}

void cmd_stack(int argc, char **argv)
{
    vector<pair<string, Thread*> > taskList;

    const char *mapper[] = { "Inactive",
                             "Ready",
                             "Running",
                             "WaitingDelay",
                             "WaitingInterval",
                             "WaitingOr",
                             "WaitingAnd",
                             "WaitingSempahore",
                             "WaitingMailbox",
                             "WaitingMutex"
                           };

    //simply add your task to the list...
    taskList.push_back(make_pair((string)"AnalyticsLogger",  GLOBAL_analyticsLogger_thread));
    taskList.push_back(make_pair((string)"ConfigHandler",    GLOBAL_configHandler_thread));
    taskList.push_back(make_pair((string)"ControlTask",      GLOBAL_controlTask_thread));
    taskList.push_back(make_pair((string)"ModbusMaster",     GLOBAL_modbusMaster_thread));
    taskList.push_back(make_pair((string)"OutputTask",       GLOBAL_outputTask_thread));

    for ( vector<pair<string, Thread*> >::iterator pos = taskList.begin();
            pos != taskList.end(); ++ pos) {
        printf("\r %-32s size/free/used/max = %5u/%5u/%5u/%5u\tpri=%u state=%-20s\n",
               pos->first.c_str(),
               pos->second->stack_size(),
               pos->second->free_stack(),
               pos->second->used_stack(),
               pos->second->max_stack(),
               pos->second->get_priority(),
               mapper[pos->second->get_state()]);
    }

    printf("\r\n");
}

void cmd_version(int argc, char **argv)
{
    printf("\rversion: %u.%u.%u (%s)\n\r\n",    MAJOR_VERSION_NUMBER,
           MINOR_VERSION_NUMBER,
           PATCH_VERSION_NUMBER,
           PROJECT_CODE_NAME);
}

void cmd_help(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    const command_table_t *tblPtr = cmdlist;

    while (tblPtr->command) {
        printf("\r%-32s:\t%s\n", tblPtr->command, tblPtr->description);
        tblPtr++;
    }
    printf("\r\n");
}

void cmd_v7(int argc, char **argv)
{
    struct v7 *v7 = v7_create();
    v7_val_t exec_rc;
    const char *js_code = "print(\"Hello World!\")";

    v7_exec(v7, js_code, &exec_rc);
    printf("\r->exec_rc = %d\r\n", (int)exec_rc);
    v7_destroy(v7);
}

void cmd_json(int argc, char **argv)
{
    const char buf[] = {
        "{"
        "\"tag1\":\"value1\" ,"
        "\"tag2\":\"value2\" "
        "}"
    };

    cJSON *root = cJSON_Parse(buf);
    printf("\rtag1 = %s\n", cJSON_GetObjectItem(root, "tag1")->valuestring);
    printf("\rtag2 = %s\n", cJSON_GetObjectItem(root, "tag2")->valuestring);
    cJSON_Delete(root);
}

/*****************************************************************************
 * Function:        cmd_outputs
 * Description:     display outputs
 ****************************************************************************/
void cmd_outputs(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    DisplayOutputs();
}

void cmd_formatFS(int argc, char **argv)
{
    mfs fs0(0xA0);
    console.printf("\n\r\n\r[mFS] Formatting EEPROM.....................");
    int bad_blocks = fs0.mkfs(true);
    console.printf(" found %d bad blocks\r\n", bad_blocks);
}

void cmd_writeFile(int argc, char **argv)
{
    mfs fs0(0xA0);

    char filename[FILENAME_LENGTH];
    memset( filename, '\0', FILENAME_LENGTH );
    strncpy( filename, argv[1], FILENAME_LENGTH-1 );

    char *file_buf = (char*) malloc(MAX_FILE_SIZE);
    memset( file_buf, '\0', MAX_FILE_SIZE);
    snprintf(file_buf, MAX_FILE_SIZE, "1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890");
    printf("%s\r\n", file_buf);
    if( GLOBAL_mdot->saveUserFile( filename, (void *)file_buf, MAX_FILE_SIZE ) != true ) {
        printf("Failed saveUserFile\r\n");
    }
    free(file_buf);

    return;
}

void cmd_readFile(int argc, char **argv)
{
    char filename[FILENAME_LENGTH];
    memset( filename, '\0', FILENAME_LENGTH );
    strncpy( filename, argv[1], FILENAME_LENGTH-1 );
    int file_size = (atoi(argv[2]));

    char *file_buf = (char*) malloc(MAX_FILE_SIZE*2);
    memset( file_buf, '\0', MAX_FILE_SIZE*2);
    if( GLOBAL_mdot->readUserFile( filename, (void *)file_buf, file_size ) != true ) {
        printf("Failed readUserFile\r\n");
    }
    printf("%s\r\n", file_buf);
    free(file_buf);

    return;
}

void cmd_deleteFile(int argc, char **argv)
{
    char filename[FILENAME_LENGTH];
    memset( filename, '\0', FILENAME_LENGTH );
    strncpy( filename, argv[1], FILENAME_LENGTH-1 );

    if( GLOBAL_mdot->deleteUserFile( filename ) != true ) {
        printf("Failed readUserFile\r\n");
    }

    return;
}

void cmd_lsFile( int argc, char ** argv )
{

    std::vector<std::string>::iterator file;
    std::vector<std::string> file_list;
    file_list = GLOBAL_mdot->listUserFiles();
    for(file = file_list.begin(); file != file_list.end(); ++file) {
        printf("%s\r\n", file->c_str() );
    }

    mfs fs0(0xA0);
    // Get number of free blocks
    char iFreeBlocks = fs0.free();
    // Calculate amount of space used
    unsigned int iSpaceUsed = VOL_SIZE - (iFreeBlocks*BS);
    // Summary
    printf("\n\r%u/%u kB space used, %u blocks free\n\r\n\r", iSpaceUsed/1024, VOL_SIZE/1024, iFreeBlocks);
}

/**
 * Serial read function.
 */
int func_read(char *buf, int cnt)
{
    for (int i = 0; i < cnt; i++) {
        buf[i] = console.getc();
    }

    return 0;
}

/**
 * Serial write function.
 */
int func_write(const char *buf, int cnt)
{
    for (int i = 0; i < cnt; i++) {
        console.putc(buf[i]);
    }
    return 0;
}

/**
 * Callback function for ntshell module.
 */
int func_cb_ntshell(const char *text)
{
    return ntopt_parse(text, func_cb_ntopt);
}

/**
 * Callback function for ntopt module.
 */
void func_cb_ntopt(int argc, char **argv)
{
    if (argc == 0) {
        return;
    }
    int execnt = 0;
    const command_table_t *p = &cmdlist[0];
    while (p->command != NULL) {
        if (strcmp(argv[0], p->command) == 0) {
            p->func(argc, argv);
            execnt++;
        }
        p++;
    }
    if (execnt == 0) {
        printf("Command not found.\r\n");
    }
    wait_ms(250);
}

#if 0
/*****************************************************************************
 * Function:        cmd_createSequence
 * Description:     create an administrative control
 *
 * @param           argc-> number of args
 * @param           argv-> control name, control type
 * @return          none
 *****************************************************************************/
void cmd_createSequence(int argc, char **argv)
{
    char buf[MAX_FILE_SIZE*2];

    // let's crreate the sequence control file
    std::string filename = "control_seq_SLUG-DOSE.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"SLUG-DOSE\", "
             "\"startTrigger\": \"v_slugSchedule\", "
             "\"sequence\": "
             "["
             // START PRE-BLEED elements
             "{ \"startTrigger\":\"v_alwaysTrue\", "
             "\"actions\": "
             "["
             "{ \"action\": \"create\", \"id\": \"PRE-BLEED-SP\" }, "
             "{ \"action\": \"create\", \"id\": \"GUARD-TM\" }"
             "]," // end actions array
             "\"stopTrigger\": \"v_PreBleedDone\" },"

             // DELETE PRE-BLEED elements
             "{ \"startTrigger\":\"v_alwaysTrue\", "
             "\"actions\": "
             "["
             "{ \"action\": \"delete\", \"id\": \"PRE-BLEED-SP\" }, "
             "{ \"action\": \"delete\", \"id\": \"GUARD-TM\" }"
             "],"
             "\"stopTrigger\": \"v_alwaysTrue\" },"

             // SLUG-FEED elements
             "{ \"startTrigger\":\"v_alwaysTrue\", "
             "\"actions\": "
             "["
             "{ \"action\": \"create\", \"id\": \"SLUG-FEED-SP\" } "
             "],"
             "\"stopTrigger\": \"v_SlugFeedDone\" },"

             // DELETE SLUG-FEED elements
             "{ \"startTrigger\":\"v_alwaysTrue\", "
             "\"actions\": "
             "["
             "{ \"action\": \"delete\", \"id\": \"SLUG-FEED-SP\" } "
             "],"
             "\"stopTrigger\": \"v_alwaysTrue\" }"
             "] " // end sequence array
             "} ");

    printf("String Length=%d\r\n", strlen(buf) );
    bool rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, sizeof(buf));
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }
    // the pre-bleed setpoint control
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\": \"PRE-BLEED-SP\","
             "\"priority\": \"750\", "
             "\"input\": \"i_bdcond\" ,"
             "\"output\": \"o_rly01\" ,"
             "\"setpoint\": \"1750\", "
             "\"prodfact\": \"\", "
             "\"actingDir\": \"1\", "
             "\"tol\": \"5\" "
             "}");
    filename = "seq_SLUG-DOSE_PRE-BLEED-SP.json";
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void*)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // OUTPUT: Virtual Output - this is the START TRIGGER fro the control
    filename = "vregister_slugSchedule.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_slugSchedule\", "
             "\"value\": \"0\" "
             "}");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // VIRTUAL REGISTER: always True
    filename = "vregister_alwaysTrue.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_alwaysTrue\", "
             "\"value\": \"1\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // VIRTUAL REGISTER: v_GuardTimer
    filename = "vregister_GuardTimer.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_GuardTimer\", "
             "\"value\": \"0\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // VIRTUAL REGISTER: v_PreBleedDone
    filename = "vreg_PreBleedDone.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_PreBleedDone\", "
             "\"value\": \"0\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // VIRTUAL REGISTER: v_SlugFeedDone
    filename = "vreg_SlugFeedDone.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_SlugFeedDone\", "
             "\"value\": \"0\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }


    // CONTROL: GUARD-TIMER
    filename = "seq_SLUG-DOSE_GUARD-TM.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":\"GUARD-TM\","
             "\"output\":\"v_GuardTimer\","
             "\"priority\":\"750\","
             "\"day\":\"\","
             "\"startHour\":\"\","
             "\"startMin\":\"\","
             "\"startSec\":\"\","
             "\"week\":\"\","
             "\"duration\":\"60\" "
             "}");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void*)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("failed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // the pre-bleed setpoint control
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\": \"SLUG-FEED-SP\","
             "\"priority\": \"750\", "
             "\"input\": \"i_orp01\" ,"
             "\"output\": \"o_rly02\" ,"
             "\"setpoint\": \"400\", "
             "\"prodfact\": \"\", "
             "\"actingDir\": \"1\", "
             "\"tol\": \"5\" "
             "}");
    filename = "seq_SLUG-DOSE_SLUG-FEED-SP.json";
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void*)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }
}
#endif

// PRELOAD command, used to create all the pertinent inputs, outputs, and
// controls needed to achieve a basic cooling water application
void cmd_preload(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    char buf[MAX_FILE_SIZE];
    bool rc;

    // PRELOADER:
    // JavaScripts:
    //      js_noFlowDelay.js           // implement 10 minute on delay for flow switch
    //      js_sum.js                   // sum two registers and store in register
    //      js_diff.js                  // diff two registers and store in register
    //      js_mul.js                   // mul two registers and store in register
    //      js_div.js                   // div two registers and store in register
    //      js_equ.js                   // equ set one register equal to another register
    //
    // Inputs:
    //      input_i_bdcond.json         // conductivity probe
    //      input_i_bdcond_temp.json    // conductivity probe : temperature
    //      input_i_flowsw01.json       // flow switch
    //      input_i_orp01.json          // ORP probe
    //      input_i_ph01.json           // pH probe
    //      input_i_ph01_temp.json      // pH probe : temperature
    //      input_i_tag01.json          // tag (flu)
    //      input_i_tra01.json          // Trasar
    //
    // Outputs:
    //      output_o_rly01.json         // relay-1
    //      output_o_rly02.json         // relay-2
    //
    // Standard Controls:
    //      control_sp_i_bd01.json        // blowdown
    //      control_sp_i_tra01.json       // Trasar
    //
    // Control Algorithms:
    //      control_ca_eq1.json         // == 1
    //      control_ca_eq129.json       // == 129
    //
    // Composite Controls:
    //      control_comp_flow.json      // flow override
    //      control_comp_lockout.json   // lockout blowdown

    std::string filename = "ble_device_name.json";

    snprintf(buf, sizeof(buf), "{\"id\":\"ICE-Ecolab\"}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    filename = "vreg_const_1000.json";

    // Constant: 1000.0
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"v_Const_1000\", "
             "\"value\":     \"1000.0\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

#ifdef EXECUTE_SCRIPT

    filename = "vreg_noFlowDelaySig.json";

    // Virtual Register: v_noFlowDelaySig
    // Used to generate on delay timing for flow override.
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"v_noFlowDelaySig\", "
             "\"value\":     \"1\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "vreg_noFlowTimeStamp.json";

    // Virtual Register: v_noFlowTimeStamp
    // Used to generate on delay timing for flow override.
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"v_noFlowTimeStamp\", "
             "\"value\":     \"0\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_noFlowDelay.js";

    // JavaScript: sum(a, b, c)
    // a = Flow Input Signal - this is the signal we are doing the on delay timing for
    // b = v_noFlowDelaySig - signal generated after No Flow condition exsits for 10 minutes
    // c = v_noFlowTimeStamp - mark of when the no flow signal first started
    //
    // "\"args\":[{\"arg\":\"i_flowsw01\"},{\"arg\":\"v_noFlowDelaySig\"},{\"arg\":\"v_noFlowTimeStamp\"}],"
    //
    snprintf(buf, sizeof(buf),
             "var noFlowDelay=function(a,b,c){"
             "f_state=getRegister(a);"
             "if(f_state==1){"
             // we have flow on the skid, reset timestamp to 0
             // and reset the "delayed" signal to indicate we have flow
             "setRegister(c,0);"
             "setRegister(b,f_state);"
             "}else{"
             // we don't have flow on the skid
             "curr_time=getTime();"
             "st_tstamp=getRegister(c);"
             "if(st_tstamp==0) {"
             // this is the 1st read of no-flow
             // mark the start of the delay timing
             "setRegister(c,curr_time);"
             "}else{"
             // determine how long we have been doing the delay timing.
             "diff_time=curr_time-st_tstamp;"
             //"print(' Delay='+diff_time+'\r');"
             "if(diff_time>=600){"
             // been doing the delay timing for at least 10 minutes
             // set the delayed signal to equal the actual flow switch
             "setRegister(b,f_state);"
             "}"
             "}"
             "}"
             "return 1;"
             "};" );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_sum.js";

    // JavaScript: sum(a, b, c)
    snprintf(buf, sizeof(buf),
             "var sum = function(a, b, c) {"
             "res = (getRegister(a) + getRegister(b));"
             "setRegister(c,res);"
             "return res;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_diff.js";

    // JavaScript: diff(a, b, c)
    snprintf(buf, sizeof(buf),
             "var diff = function(a, b, c) {"
             "res = (getRegister(a) - getRegister(b));"
             "setRegister(c,res);"
             "return res;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_div.js";

    // JavaScript: div(a, b, c)
    snprintf(buf, sizeof(buf),
             "var div = function(a, b, c) {"
             "res = (getRegister(a) / getRegister(b));"
             "setRegister(c,res);"
             "return res;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_mul.js";

    // JavaScript: mul(a, b, c)
    snprintf(buf, sizeof(buf),
             "var mul = function(a, b, c) {"
             "res = (getRegister(a) * getRegister(b));"
             "setRegister(c,res);"
             "return res;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "js_equ.js";

    // JavaScript: equ(a, b)
    snprintf(buf, sizeof(buf),
             "var equ = function(a, b) {"
             "res = getRegister(a);"
             "setRegister(b,res);"
             "return res;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "exe_js_div_cond_temp01.js";

    // Execute JavaScript: DIV_COND_TEMP01
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"DIV_COND_TEMP01\","
             "\"script\":\"div\","
             "\"args\":[{\"arg\":\"i_cond_temp01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_cond_temp01\"}]"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    filename = "exe_js_div_ph01.js";

    // Execute JavaScript: DIV_PH01
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"DIV_PH01\","
             "\"script\":\"div\","
             "\"args\":[{\"arg\":\"i_ph01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_ph01\"}]"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    filename = "exe_js_prebleed.js";
    // Execute JavaScript: PREBLEED_DONE.json
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"PREBLEED_DONE\","
             "\"script\":\"prebleed_done\","
             // in: o_rly01
             // in: v_pbTimer
             // out" v_preBleedDone
             "\"args\":[{\"arg\":\"o_rly01\"},{\"arg\":\"v_pbTimer\"},{\"arg\":\"v_preBleedDone\"}]"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    /*
        filename = "exe_js_div_ph_temp01.js";

        // Execute JavaScript: DIV_PH_TEMP01
        snprintf(buf, sizeof(buf),
                 "{ "
                 "\"id\":\"DIV_PH_TEMP01\","
                 "\"script\":\"div\","
                 "\"args\":[{\"arg\":\"i_ph_temp01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_ph_temp01\"}]"
                 "};"
                );
        rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
        if ( rc != true ) {
            printf("\rFailed to save %s\n", filename.c_str());
            return;
        } else {
            printf("\r...generated %s\n", filename.c_str());
        }

        Thread::wait(1000);

        filename = "exe_js_no_flow_delay.js";

        // Execute JavaScript: NO_FLOW_DELAY
        snprintf(buf, sizeof(buf),
                 "{ "
                 "\"id\":\"NO_FLOW_DELAY\","
                 "\"script\":\"noFlowDelay\","
                 "\"args\":[{\"arg\":\"i_flowsw01\"},{\"arg\":\"v_noFlowDelaySig\"},{\"arg\":\"v_noFlowTimeStamp\"}]"
                 "};"
                );
        rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
        if ( rc != true ) {
            printf("\rFailed to save %s\n", filename.c_str());
            return;
        } else {
            printf("\r...generated %s\n", filename.c_str());
        }

        Thread::wait(1000);
    */
#endif

    filename = "input_i_bdcond01.json";

    // INPUT: Conductivity
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"i_bdcond01\","
             "\"name\":      \"Tower Conductivity\", "
             "\"units\":     \"uS\","
             "\"min\":       \"0\","
             "\"max\":       \"6000\","
             "\"node\":      \"21\","
             "\"reg\":       \"18\","
             "\"rtype\":     \"4\","
             "\"type\":      \"1\","
             "\"size\":      \"2\","
             "\"order\":     \"2\","
             "\"fmt\":       \"%%.2f\","
             "\"cmd\":       \"\","
             "\"args\":      [],"
             "\"rfreq\":     \"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: Conductivity Temperature
    filename = "input_i_cond_temp01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"i_cond_temp01\","
             "\"name\":\"Temp Conductivity\","
             "\"units\":\"C\","
             "\"min\":\"0\","
             "\"max\":\"80\","
             "\"node\":\"21\","
             "\"reg\":\"10\","
             "\"rtype\":\"4\","
             "\"type\":\"1\","
             "\"size\":\"2\","
             "\"order\":\"2\","
             "\"fmt\":\"%%.2f\","
             "\"cmd\":\"div\","
             "\"args\":[{\"arg\":\"i_cond_temp01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_cond_temp01\"}],"
             "\"rfreq\":\"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: Flow Switch
    filename = "input_i_flowsw01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"i_flowsw01\","
             "\"name\":      \"Flow\","
             "\"units\":     \"\","
             "\"min\":       \"0\","
             "\"max\":       \"1\","
             "\"node\":      \"0\","
             "\"reg\":       \"1\","
             "\"rtype\":     \"0\","
             "\"type\":      \"3\","
             "\"size\":      \"2\","
             "\"order\":     \"0\","
             "\"fmt\":       \"%%d\","
             "\"cmd\":       \"\","
             "\"args\":      [],"
             "\"rfreq\":     \"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: ORP
    filename = "input_i_orp01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"i_orp01\","
             "\"name\":      \"ORP\","
             "\"units\":     \"mV\","
             "\"min\":       \"0\","
             "\"max\":       \"10\","
             "\"node\":      \"23\","
             "\"reg\":       \"14\","
             "\"rtype\":     \"4\","
             "\"type\":      \"1\","
             "\"size\":      \"2\","
             "\"order\":     \"2\","
             "\"fmt\":       \"%%.2f\","
             "\"cmd\":       \"\","
             "\"args\":      [],"
             "\"rfreq\":     \"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: pH
    filename = "input_i_ph01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"i_ph01\","
             "\"name\":\"pH\","
             "\"units\":\"pH\","
             "\"min\":\"0\","
             "\"max\":\"10\","
             "\"node\":\"22\","
             "\"reg\":\"18\","
             "\"rtype\":\"4\","
             "\"type\":\"1\","
             "\"size\":\"2\","
             "\"order\":\"2\","
             "\"fmt\":\"%%.2f\","
             "\"cmd\":\"div\","
             "\"args\":[{\"arg\":\"i_ph01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_ph01\"}],"
             "\"rfreq\":\"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: pH Temperature
    filename = "input_i_ph01_temp.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"i_ph_temp01\","
             "\"name\":\"Temp pH\","
             "\"units\":\"C\","
             "\"min\":\"0\","
             "\"max\":\"10\","
             "\"node\":\"22\","
             "\"reg\":\"10\","
             "\"rtype\":\"4\","
             "\"type\":\"1\","
             "\"size\":\"2\","
             "\"order\":\"2\","
             "\"fmt\":\"%%.2f\","
             "\"cmd\":\"div\","
             "\"args\":[{\"arg\":\"i_ph_temp01\"},{\"arg\":\"v_Const_1000\"},{\"arg\":\"i_ph_temp01\"}],"
             "\"rfreq\":\"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: Tag
    filename = "input_i_tag01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"i_tag01\","
             "\"name\":      \"Tag\", "
             "\"units\":     \"PPM\",    "
             "\"min\":       \"0\",      "
             "\"max\":       \"300\",    "
             "\"node\":      \"1\",      "
             "\"reg\":       \"11\",      "
             "\"rtype\":     \"4\",      "
             "\"type\":      \"0\",      "
             "\"size\":      \"2\",      "
             "\"order\":     \"2\",      "
             "\"fmt\":       \"%%.2f\",   "
             "\"cmd\":       \"\",       "
             "\"args\":      [],"
             "\"rfreq\":     \"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // INPUT: Trasar
    filename = "input_i_tra01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"i_tra01\","
             "\"name\":      \"Trasar\", "
             "\"units\":     \"PPM\",    "
             "\"min\":       \"0\",      "
             "\"max\":       \"300\",    "
             "\"node\":      \"1\",      "
             "\"reg\":       \"9\",      "
             "\"rtype\":     \"4\",      "
             "\"type\":      \"0\",      "
             "\"size\":      \"2\",      "
             "\"order\":     \"2\",      "
             "\"fmt\":       \"%%.2f\",   "
             "\"cmd\":       \"\",       "
             "\"args\":      [],"
             "\"rfreq\":     \"5\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // COMMAND: Divide by 1000
    filename = "cmd_div.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"%s\", "
             "\"Operand\":\"%s\", "
             "\"Operator\":\"%s\", "
             "\"Constant\":\"%s\" } ", "div", "", "/", "1000.0");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // OUTPUT: Relay 01
    filename = "output_o_rly01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"o_rly01\", "
             "\"name\": \"Blowdown\", "
             "\"units\": \"\", "
             "\"min\":  \"0\", "
             "\"max\": \"300\", "
             "\"node\": \"0\", "
             "\"reg\": \"1\", "
             "\"rtype\": \"1\", "
             "\"type\": \"0\", "
             "\"size\": \"2\", "
             "\"order\": \"2\", "
             "\"fmt\": \"%%.2f\", "
             "\"cmd\": \"\", "
             "\"args\": [], "
             "\"rfreq\": \"5\", "
             "\"toperiod\": \"0\", "
             "\"scalelo\": \"0\", "
             "\"scalehi\": \"100\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // OUTPUT: Relay 02
    filename = "output_o_rly02.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"o_rly02\", "
             "\"name\": \"3DTS86\", "
             "\"units\": \"\", "
             "\"min\":  \"0\", "
             "\"max\": \"300\", "
             "\"node\": \"0\", "
             "\"reg\": \"2\", "
             "\"rtype\": \"1\", "
             "\"type\": \"0\", "
             "\"size\": \"2\", "
             "\"order\": \"2\", "
             "\"fmt\": \"%%.2f\", "
             "\"cmd\": \"\", "
             "\"args\": [], "
             "\"rfreq\": \"5\", "
             "\"toperiod\": \"0\", "
             "\"scalelo\": \"0\", "
             "\"scalehi\": \"100\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // SETPOINT: Blowdown
    filename = "control_sp_BLOWDOWN_01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"BLOWDOWN_01\", "
             "\"priority\": \"800\", "
             "\"input\": \"i_bdcond01\", "
             "\"output\": \"o_rly01\", "
             "\"setpoint\": \"1800\", "
             "\"prodfact\": \"\", "
             "\"actingDir\": \"1\", "
             "\"tol\": \"30\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // SETPOINT: Trasar
    filename = "control_sp_INH_TRA_01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"INH_TRA_01\", "
             "\"priority\": \"800\", "
             "\"input\": \"i_tra01\", "
             "\"output\": \"o_rly02\", "
             "\"setpoint\": \"130\", "
             "\"prodfact\": \"100\", "
             "\"actingDir\": \"0\", "
             "\"tol\": \"4\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // ALGORITHM == 0
    filename = "control_ca_EQUAL_TO_0.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":    \"EQUAL_TO_0\", "
             "\"opr\":   \"0\", "
             "\"op\":    \"==\", "
             "\"true\":   \"responseA\", "
             "\"false\":  \"nothing\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // ALGORITHM == 129
    filename = "control_ca_RELAY_ON.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":    \"RELAY_ON\", "
             "\"opr\":   \"1\", "
             "\"op\":    \"&\", "
             "\"true\":   \"responseA\", "
             "\"false\":  \"nothing\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // FLOW
    filename = "control_comp_FLOW.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":  \"FLOW\",  "
             "\"tag\": \"i_flowsw01\",  "
             "\"ca\":  \"EQUAL_TO_0\",   "
             "\"priority\": \"300\", "
             "\"entries\":  \"2\", "
             "\"outputs\": [ "
             "{"
             "\"tag\": \"o_rly01\", "
             "\"responseA\": \"fixed off\" "
             "},"
             "{"
             "\"tag\": \"o_rly02\", "
             "\"responseA\": \"fixed off\" "
             "}"
             "]"
             "}"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // LOCKOUT
    filename = "control_comp_LOCKOUT_BD.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":  \"LOCKOUT_BD\",  "
             "\"tag\": \"o_rly01\",  "
             "\"ca\":  \"RELAY_ON\",   "
             "\"priority\": \"400\", "
             "\"entries\":  \"1\", "
             "\"outputs\": [ "
             "{"
             "\"tag\": \"o_rly02\", "
             "\"responseA\": \"fixed off\" "
             "}"
             "]"
             "}"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    filename = "control_fs_BLOWDOWN_FS.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":    \"BLOWDOWN_FS\", "
             "\"input\":   \"i_bdcond01\", "
             "\"output\":  \"o_rly01\", "
             "\"priority\":\"600\", "
             "\"lfsValue\":\"700\", "
             "\"lfsDutyCycle\":\"0\", "
             "\"lfsInterval\":\"1\", "
             "\"hfsValue\":\"2700\", "
             "\"hfsDutyCycle\":\"50\", "
             "\"hfsInterval\":\"1\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to create %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }


    Thread::wait(1000);

    filename = "control_fs_TRASAR_FS.json";
    snprintf(buf, sizeof(buf),
             " {"
             "\"id\":    \"TRASAR_FS\", "
             "\"input\":   \"i_tra01\", "
             "\"output\":  \"o_rly02\", "
             "\"priority\":\"600\", "
             "\"lfsValue\":\"70\", "
             "\"lfsDutyCycle\":\"50\", "    // ON a minute, OFF a minute...
             "\"lfsInterval\":\"2\", "
             "\"hfsValue\":\"200\", "
             "\"hfsDutyCycle\":\"0\", "
             "\"hfsInterval\":\"2\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to create %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // HOLDING REGISTER: Conductivity Calibration
    filename = "hold_h_CondCmd_21.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"%s\", "
             "\"node\":\"%s\", "
             "\"sreg\":\"%s\", "
             "\"nreg\":\"%s\", "
             "\"order\":\"%s\" } ", "h_CondCmd_21", "21", "0", "3", "2");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // HOLDING REGISTER: pH Calibration
    filename = "hold_h_phCmd_22.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"%s\", "
             "\"node\":\"%s\", "
             "\"sreg\":\"%s\", "
             "\"nreg\":\"%s\", "
             "\"order\":\"%s\" } ", "h_phCmd_22", "22", "0", "3", "2");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);


    printf("\r\nIssue \"reset\" command to invoke changes\r\n\r\n\r\n");

}

/*****************************************************************************
 * Function:        cmd_cif
 * Description:     create input file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_cif(int argc, char **argv)
{
    if ( argc != 6 ) {
        printf("\rusage:   cif <fname> <input> <name> <node> <reg>\n");
        printf("\rexample: cif input_i_tra01.json i_tra01 Trasar 5 2\n");
        return;
    }

    char data_buf[MAX_FILE_SIZE];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":       \"%s\", "
             "\"name\":     \"%s\", "
             "\"units\":    \"PPM\", "
             "\"min\":      \"0\", "
             "\"max\":      \"300\", "
             "\"node\":     \"%s\", "
             "\"reg\":      \"%s\", "
             "\"rtype\":    \"1\", "
             "\"type\":     \"0\", "
             "\"size\":     \"2\", "
             "\"order\":    \"2\", "
             "\"rfreq\":    \"5\", "
             "\"cmd\":       \"\","
             "\"args\":      [],"
             "\"fmt\":      \"%%.2f\" } ", argv[2], argv[3], argv[4], argv[5]);

    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, MAX_FILE_SIZE);
    if( status != true ) {
        printf("(%d)save file failed, status=%d", __LINE__, status);
    }

    printf("Sending Mail To ModbusMasterMailBox, filename=%s", argv[1]);
    ModbusMasterReq_t *mail = ModbusMasterMailBox.alloc();
    mail->action = ACTION_READ_FILE;
    strncpy( mail->msg, argv[1], (sizeof(mail->msg)-1));
    ModbusMasterMailBox.put(mail);
}

/*****************************************************************************
 * Function:        cmd_destroy
 * Description:     destroy a control
 *
 * @param           argc-> number of arguments
 * @param           argv-> control name, control type
 * @return          none
 *****************************************************************************/
void cmd_destroy(int argc, char **argv)
{
    if ( argc != 3 ) {
        printf("\r\nusage: destroy-control [controlName] [controlType]\n");
        printf("\rcontrolType-> 0=timer, 1=PID, 2=setpoint, 3=composite, 4=manual, 5=sequence, 6=failsafe, 7=sensor error\r\n");
        return;
    }

    // send a message to the configuration handler to destroy the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_DESTROY;
    msg->control = (Control_t) atoi(argv[2]);
    strncpy(msg->controlFile, argv[1], sizeof(msg->controlFile)-1);

    printf("%s: Sending a destroy request for control %s\r\n",
           __func__, msg->controlFile);

    ConfigHandlerMailBox.put(msg);
    printf("\r\n");
    return;
}

/*****************************************************************************
 * Function:        cmd_cof
 * Description:     create output file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_cof(int argc, char **argv)
{
    // OUTPUT: Relay 01
    char buf[MAX_FILE_SIZE];
    std::string filename = "output_o_rly01.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"o_rly01\", "
             "\"name\": \"Blowdown\", "
             "\"units\": \"\", "
             "\"min\":  \"0\", "
             "\"max\": \"300\", "
             "\"node\": \"0\", "
             "\"reg\": \"1\", "
             "\"rtype\": \"1\", "
             "\"type\": \"0\", "
             "\"size\": \"2\", "
             "\"order\": \"2\", "
             "\"fmt\": \"%%.2f\", "
             "\"cmd\": \"\", "
             "\"rfreq\": \"5\", "
             "\"toperiod\": \"0\", "
             "\"scalelo\": \"0\", "
             "\"scalehi\": \"100\" }");
    bool rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    Thread::wait(1000);

    // OUTPUT: Relay 02
    filename = "output_o_rly02.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"o_rly02\", "
             "\"name\": \"3DTS86\", "
             "\"units\": \"\", "
             "\"min\":  \"0\", "
             "\"max\": \"300\", "
             "\"node\": \"0\", "
             "\"reg\": \"2\", "
             "\"rtype\": \"1\", "
             "\"type\": \"0\", "
             "\"size\": \"2\", "
             "\"order\": \"2\", "
             "\"fmt\": \"%%.2f\", "
             "\"cmd\": \"\", "
             "\"rfreq\": \"5\", "
             "\"toperiod\": \"0\", "
             "\"scalelo\": \"0\", "
             "\"scalehi\": \"100\" }");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }
}

/*****************************************************************************
 * Function:        cmd_modmap
 * Description:     dump modbus register map
 *****************************************************************************/
void cmd_modmap(int argc, char **argv)
{

    UNUSED(argc);
    UNUSED(argv);
    ModbusValue value;

    std::map<std::string, ModbusRegister>::iterator iter;
    for (iter = ModbusRegisterMap.begin(); iter != ModbusRegisterMap.end(); ++iter) {
        ModbusMasterReadRegister( iter->first, &value );
        printf("tag=%-24s node=%-4d reg=%-4d rtype=%-2d size=%-2d order=%-2d value=%-12.2f errflag=%-2d argc=%-2d arg[0]=%-24s\r\n",
               iter->first.c_str(), iter->second.node, iter->second.reg,
               iter->second.rtype, iter->second.size, iter->second.order,
               value.value, value.errflag, iter->second.argc, iter->second.argv[0].c_str() );
    }
}

void cmd_createVreg(int argc, char **argv)
{
    if ( argc != 4 ) {
        printf("\rusage: create-vreg <filename> <vregId> <value>\n");
        printf("\rusage: create-vreg vreg_alwaysTrue.json v_alwaysTrue 1\n");
        return;
    }

    char buf[MAX_FILE_SIZE];
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":        \"%s\", "
             "\"value\":     \"%s\" }", argv[2], argv[3]);
    bool rc = GLOBAL_mdot->saveUserFile(argv[1], (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", argv[1]);
        return;
    } else {
        printf("\r...generated %s\n", argv[1]);
    }
}

//
void cmd_createCAlg(int argc, char **argv)
{
    if ( argc != 1 ) {
        printf("\rusage: create-ca control_ca_equal.json");
        return;
    }

    char buf[MAX_FILE_SIZE];
    std::string filename = "control_ca_eq1.json";
    snprintf(buf, sizeof(buf),
             " {"
             "\"id\":    \"EQUAL_TO_1\", "
             "\"opr\":   \"1\", "
             "\"op\":    \"==\", "
             "\"true\":   \"responseA\", "
             "\"false\":  \"nothing\" "
             "}");

    bool rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

// send a message to the configuration handler to create the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_ALGORITHM;
    strncpy(msg->controlFile, filename.c_str(), sizeof(msg->controlFile)-1);

    ConfigHandlerMailBox.put(msg);

    Thread::wait(2000);

// == 129
    filename = "control_ca_eq129.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":    \"EQUAL_TO_1\", "
             "\"opr\":   \"1\", "
             "\"op\":    \"==\", "
             "\"true\":   \"responseA\", "
             "\"false\":  \"nothing\" "
             "}");

    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save user file %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // send a message to the configuration handler to create the control
    msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_ALGORITHM;
    strncpy(msg->controlFile, "control_ca_greq1.json", sizeof(msg->controlFile)-1);

    ConfigHandlerMailBox.put(msg);
}

/*****************************************************************************
 * Function:        cmd_createManual
 * Description:     create a manual control
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_createManual(int argc, char **argv)
{
    std::string relayState;
    if ( argc != 6 ) {
        printf("\rusage:   create-mn <filename> <id> <output> <state> <duration>\n");
        printf("\rexample: create-mn control_mn_rly01.json man-1 o_rly1 on 30\r\n");
        printf("\r<duration> specified in seconds, 0 for contiuous\n");
        return;
    }

    string state(argv[4]);

    if ( state == "on" ) {
        relayState = "1";
    } else if ( state == "off" ) {
        relayState = "0";
    } else {
        printf("\r<state> must be on or off\r\n");
        return;
    }

    unsigned int duration = atoi(argv[5]);
    unsigned int type;
    if ( duration == 0 ) {
        type = MANUAL_CONTROL_TYPE_CONTINUOUS;
    } else {
        type = MANUAL_CONTROL_TYPE_TIMED;
    }

    char data_buf[MAX_FILE_SIZE];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\",  "
             "\"output\":       \"%s\",  "
             "\"type\":         \"%d\",   "
             "\"priority\":     \"100\", "
             "\"duration\":     \"%d\",   "
             "\"setpoint\":     \"0\",   "
             "\"state\":        \"%s\",  "
             "\"percent\":      \"100\"  }", argv[2], argv[3], type, duration, relayState.c_str()
            );

    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, MAX_FILE_SIZE);
    if( status != true ) {
        printf("(%d)save file failed, status=%d", __LINE__, status);
        return;
    }

    // send a message to the configuration handler to create the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_MANUAL;
    strncpy(msg->controlFile, argv[1], sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
    printf("\r\n");
    return;
}

/*****************************************************************************
 * Function:        cmd_createSError
 * Description:     create a sensoe error control
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_createSError(int argc, char **argv)
{
    if ( argc != 7 ) {
        printf("\rusage:   create-se <filename> <id> <input> <output> <duty> <interval>\n");
        printf("\rexample: create-se control_se_bdcond.json se-1 i_bdcond o_rly01 50 10\n");
        return;
    }

    char data_buf[MAX_FILE_SIZE];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":        \"%s\",  "
             "\"input\":     \"%s\",  "
             "\"output\":    \"%s\",  "
             "\"priority\":  \"459\", "
             "\"dutyCycle\": \"%d\",  "
             "\"interval\":  \"%d\"  }",
             argv[2], argv[3], argv[4], atoi(argv[5]), atoi(argv[6])
            );

    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, MAX_FILE_SIZE);
    if( status != true ) {
        printf("(%d)save file failed, status=%d", __LINE__, status);
        return;
    }

    // send a message to the configuration handler to create the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_SENSOR_ERROR;
    strncpy(msg->controlFile, argv[1], sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for sensor error control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
    printf("\r\n");
    return;
}

/*****************************************************************************
 * Function:        cmd_createSetpoint
 * Description:     create control file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_createSetpoint(int argc, char **argv)
{
    if ( argc != 8 ) {
        printf("\rusage:   create-sp <filename> <id> <input> <output> <sp> <dir> <tol>\n");
        printf("\rexample: create-sp control_sp_1.json bd i_cond o_rly1 2000 1 15\n");
        return;
    }

    if ( strncmp(argv[1], CONTROL_SP_STR, strlen(CONTROL_SP_STR)) != 0 ) {
        printf("\rFilename must be prefixed with control_sp_*\n");
        return;
    }

    char data_buf[MAX_FILE_SIZE];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\", "
             "\"priority\":     \"800\","
             "\"input\":        \"%s\", "
             "\"output\":       \"%s\", "
             "\"setpoint\":     \"%s\","
             "\"prodfact\":     \"100\","
             "\"actingDir\":    \"%s\", "
             "\"halert\":       \"115\","
             "\"lalert\":       \"85\", "
             "\"hfs\":          \"130\","
             "\"lfs\":          \"70\", "
             "\"tol\":          \"%s\"  }", argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);

    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, MAX_FILE_SIZE);
    if( status != true ) {
        printf("(%d)save file failed, status=%d", __LINE__, status);
        return;
    }

    // send a message to the configuration handler to create the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_SETPOINT;
    strncpy(msg->controlFile, argv[1], sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
    printf("\r\n");
    return;
}

/*****************************************************************************
 * Function:        cmd_createTimer
 * Description:     create control file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_createTimer(int argc, char **argv)
{
    if ( argc != 10 ) {
        printf("\rusage:   create-tm <filename> <id> <output> <day> <hh> <mm> <ss> <duration> <week>\n");
        printf("\rexample: create-tm control_tm_rly01.json o_rly01 wed 12 00 00 60\n");
        printf("\r      <day> is sun, mon, tue, wed, thu, fri, sat\n");
        printf("\r      <duration> is in seconds\n");
        printf("\r      <week> is every, first, second, third, fourth, last, everyother\n\r\n");
        return;
    }

    if ( strncmp(argv[1], CONTROL_TM_STR, strlen(CONTROL_TM_STR)) != 0 ) {
        printf("\rFilename must be prefixed with control_tm_*\n");
        return;
    }

    char data_buf[MAX_FILE_SIZE];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":        \"%s\", "
             "\"output\":    \"%s\", "
             "\"priority\":  \"750\", "
             "\"day\":       \"%s\", "
             "\"startHour\": \"%s\", "
             "\"startMin\":  \"%s\", "
             "\"startSec\":  \"%s\", "
             "\"duration\":  \"%s\", "
             "\"week\":      \"%s\" } ",
             argv[2], argv[3], argv[4], argv[5], argv[6],
             argv[7], argv[8], argv[9]);


    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, MAX_FILE_SIZE);
    if( status != true ) {
        printf("(%d)save file failed, status=%d", __LINE__, status);
        return;
    }

    // send a message to the configuration handler to create the control
    ConfigMessage_t *msg  = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_TIMER;
    strncpy(msg->controlFile, argv[1], sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
    printf("\r\n");
    return;
}

void cmd_createFailsafe(int argc, char **argv)
{
    char buf[MAX_FILE_SIZE];
    bool status;

    std::string filename = "control_fs_rly01.json";
    snprintf(buf, sizeof(buf),
             "{"
             "\"id\":    \"BLOWDOWN-FS\", "
             "\"input\":   \"i_bdcond01\", "
             "\"output\":  \"o_rly01\", "
             "\"priority\":\"700\", "
             "\"lfsValue\":\"700\", "
             "\"lfsDutyCycle\":\"0\", "
             "\"lfsInterval\":\"1\", "
             "\"hfsValue\":\"2700\", "
             "\"hfsDutyCycle\":\"50\", "
             "\"hfsInterval\":\"1\" "
             "}");

    status = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( status != true ) {
        printf("\rFailed to create %s\n", filename.c_str());
        return;
    } else {
        printf("\r   created %s\n", filename.c_str());
    }

    ConfigMessage_t *msg = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_FAILSAFE;
    strncpy(msg->controlFile, filename.c_str(), sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
    Thread::wait(1000);

    filename = "control_fs_rly02.json";
    snprintf(buf, sizeof(buf),
             " {"
             "\"id\":    \"TRASAR-FS\", "
             "\"input\":   \"i_tra01\", "
             "\"output\":  \"o_rly02\", "
             "\"priority\":\"700\", "
             "\"lfsValue\":\"70\", "
             "\"lfsDutyCycle\":\"20\", "
             "\"lfsInterval\":\"15\", "
             "\"hfsValue\":\"200\", "
             "\"hfsDutyCycle\":\"0\", "
             "\"hfsInterval\":\"15\" "
             "}");

    status = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( status != true ) {
        printf("\rFailed to create %s\n", filename.c_str());
        return;
    } else {
        printf("\r   created %s\n", filename.c_str());
    }

    msg = ConfigHandlerMailBox.alloc();
    memset(msg, 0, sizeof(ConfigMessage_t));
    msg->action  = ACTION_CREATE;
    msg->control = CONTROL_FAILSAFE;
    strncpy(msg->controlFile, filename.c_str(), sizeof(msg->controlFile)-1);

    printf("%s: Sending a create request for control %s type = %u\r\n",
           __func__, msg->controlFile, msg->control);

    ConfigHandlerMailBox.put(msg);
}

/*****************************************************************************
 * Function:        cmd_logLevel
 * Description:     get or set the current log-level
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_logLevel(int argc, char **argv)
{
    uint8_t logLevel = 0;

    const char *mapper[] = { "NONE",
                             "FATAL",
                             "ERROR",
                             "WARNING",
                             "INFO",
                             "DEBUG",
                             "TRACE"
                           };

    if ( argc == 1 ) {
        printf("\r  current log-level set to %s\r\n",
               mapper[ICELog::getLogLevel()]);
        goto usage;
    }

    if ( argc != 2 ) {
usage:
        printf("\rusage: log-level [0-6]\n");
        printf("\r   0 = NONE\n");
        printf("\r   1 = FATAL\n");
        printf("\r   2 = ERROR\n");
        printf("\r   3 = WARNING\n");
        printf("\r   4 = INFO\n");
        printf("\r   5 = DEBUG\n");
        printf("\r   6 = TRACE\r\n");
        return;
    }

    logLevel = atoi(argv[1]);
    if ( logLevel > 6 )
        goto usage;

    // reassign the log level
    printf("...setting log-level to %s\r\n", mapper[logLevel]);
    ICELog::setLogLevel(logLevel);
    printf("\r\n");
}


/*****************************************************************************
 * Function:        cmd_vregmap
 * Description:     show virtual register map
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
extern std::map<std::string,RegisterValue> RegisterValueMap;

void cmd_vregmap(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    std::map<std::string, RegisterValue>::iterator iter;
    for (iter = RegisterValueMap.begin(); iter != RegisterValueMap.end(); ++iter) {
        printf("id=%s, value=%.4f\r\n", iter->first.c_str(), iter->second.float_value );
    }
}

void cmd_testPreBleed(int argc, char **argv)
{
    char buf[MAX_FILE_SIZE];

    // OUTPUT (virtual): variable set to TRUE when pre-bleed is done
    std::string filename = "vreg_preBleedDone.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_preBleedDone\", "
             "\"value\": \"0\" "
             "}");
    bool rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // OUTPUT (virtual): variable is set to TRUE while pre-bleed time is running via timer control
    filename = "vreg_pbTimer.json";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\": \"v_pbTimer\", "
             "\"value\": \"0\" "
             "}");
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // JavaScript Executor:
    //   IN: o_rly01
    //   IN: v_pbTimer
    //   OUT: v_preBleedDone
    //
    // Description: execute the js_nor_regs() script with arguments o_rly01
    //              and v_pbTimer; stores the result in v_preBleedDone
    //
    filename = "exe_js_prebleed_done.js";
    snprintf(buf, sizeof(buf),
             "{ "
             "\"id\":\"PREBLEED_DONE\","
             "\"script\":\"nor_regs\","
             "\"args\":[{\"arg\":\"o_rly01\"},{\"arg\":\"v_pbTimer\"},{\"arg\":\"v_preBleedDone\"}]"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }

    // JavaScript: nor_regs(a, b) => c
    filename = "js_nor_regs.js";
    snprintf(buf, sizeof(buf),
             "var nor_regs = function(a, b, c) {"
             "res1 = getRegister(a);"
             "res2 = getRegister(b);"
             "if ( res1 == 0 || res2 == 0 ) { setRegister(c, 1); }"
             "return 1;"
             "};"
            );
    rc = GLOBAL_mdot->saveUserFile(filename.c_str(), (void *)buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        printf("\rFailed to save %s\n", filename.c_str());
        return;
    } else {
        printf("\r...generated %s\n", filename.c_str());
    }
}

/*****************************************************************************
 * Function:        cmd_setTime
 * Description:     set real-time clock
 *
 * @param           argc-> number of args
 * @param           argv-> input
 * @return          none
 *****************************************************************************/


void cmd_setTime(int argc, char **argv)
{
    if ( argc != 7 ) {
        printf("\rusage:   set-time <yyyy> <mm> <dd> <hh> <mm> <ss>\n");
        printf("\rexample: set-time 2017 1 24 9 0 0\r\n");
        return;
    }

    int isc = atoi( argv[6] );                              // sec
    int imn = atoi( argv[5] );                              // min
    int ihr = atoi( argv[4] );                              // hour
    int idy = atoi( argv[3] );                              // idy
    int imo = atoi( argv[2] );                              // imo
    int iyr = atoi( argv[1] );                              // year

//    printf( "\r\n%s:%d: sec(0x%x) min(0x%x) hour(0x%x) day(0x%x) mon(0x%x) year(0x%x)\r\n", __func__, __LINE__, isc, imn, ihr, idy, imo, iyr );

    rtc_set_time(iyr, imo, idy, ihr, imn, isc);
}
void getTime()
{
    char time_string[80];
    struct tm   rtc_time;
    struct tm * ts;
    time_t      curr_sec;
    int         year = 0;

    rtc_get_time(&year, &rtc_time.tm_mon, &rtc_time.tm_mday, &rtc_time.tm_hour, &rtc_time.tm_min, &rtc_time.tm_sec);
//    printf( "\r\n%s:%d:sec(0x%x) min(0x%x) hour(0x%x) day(0x%x) mon(0x%x) year(0x%x)\r\n", __func__, __LINE__, rtc_time.tm_sec, rtc_time.tm_min, rtc_time.tm_hour, rtc_time.tm_mday, rtc_time.tm_mon, year );

    rtc_time.tm_mon = rtc_time.tm_mon - 1;
    rtc_time.tm_year = year - 1900;
    curr_sec =  mktime( &rtc_time );

    ts = localtime(&curr_sec);
    strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ts);

    printf("%s\r\n", time_string);
}

void cmd_getTime(int argc, char **argv)
{
    getTime();
}