Erick / Mbed 2 deprecated ICE_BLE_TEST

Dependencies:   NaturalTinyShell_ice libmDot-12Sept mbed-rtos mbed

Fork of ICE by Erick

src/CommandParser/cmd.cpp

Committer:
jmarkel44
Date:
2016-09-27
Revision:
133:c871de2d2b90
Parent:
132:45821e189dd0
Child:
148:ee3cbaafe355
Child:
152:c03ebcda54ef

File content as of revision 133:c871de2d2b90:

/*
 * ===============================================================
 *  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 "cmd.h"
#include <mbed.h>
#include <utility>
#include "ntshell.h"
#include "ntopt.h"
#include "global.h"
#include "ConfigurationHandler.h"
#include "ModbusMasterApi.h"
#include "LogLocalApi.h"
#include "LoggerApi.h"
#include "OutputTask.h"
#include "mDot.h"
#include "rtos.h"
#include "rtc.h"

Serial serial(USBTX, USBRX);
ntshell_t ntshell;

extern mDot *GLOBAL_mdot;

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

// see cmd.h
const command_table_t cmdlist[] = {
    {"?",                   "help command",                                     cmd_help            },
    //{"create-control",      "create a control",                                 cmd_create          },
    {"cat",                 "cat a file",                                       cmd_cat             },
    {"cif",                 "create a test input file",                         cmd_cif             },
    {"cmf",                 "create a manual control file",                     cmd_cmf             },
    {"cof",                 "create a test output file",                        cmd_cof             },
    {"create-manual",       "create a manual control",                          cmd_createManual    },
    {"create-setpoint",     "create a setpoint control",                        cmd_createSetpoint  },
    {"create-timer",        "create a timer control",                           cmd_createTimer     },
    {"destroy-control",     "destroy a control",                                cmd_destroy         },
    {"heap",                "show heap statistics",                             cmd_heap            },
    {"help",                "help command",                                     cmd_help            },
    {"log-level",           "get/set mDot log level",                           cmd_logLevel        },
    {"ls",                  "list user files",                                  cmd_ls              },
    {"modify-control",      "modify a control",                                 cmd_modify          },
    {"modmap",              "dump modbus register map",                         cmd_modmap          },
    {"reset",               "reset the controller",                             cmd_reset           },
    {"reset-stats",         "reset current mDot statistics",                    cmd_resetStats      },
    {"rm",                  "remove a user file",                               cmd_rm              },
    {"rssi-stats",          "get current rssi stats",                           cmd_rssiStats       },
    {"set-time",            "set current time",                                 cmd_settime         },
    {"show-controls",       "display active controls",                          cmd_ShowControls    },
    {"show-outputs",        "dump outputs",                                     cmd_outputs         },
    {"snr-stats",           "get current SNR stats",                            cmd_snrStats        },
    {"stack",               "get thread stack usage stats",                     cmd_stack           },
    {"stats",               "get current mDot statistics",                      cmd_stats           },
    {"time",                "get current time",                                 cmd_time            },
    {"sout",                "set output",                                       cmd_sout            },
    {"simin",               "simulate input",                                   cmd_simin           },
    {"deep",                "dump EEP",                                         cmd_deep            },
    {"peep",                "push EEP",                                         cmd_peep            },
    {"ins-log",             "insert log event",                                 cmd_inslog          },


    {NULL, NULL, NULL}
};

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);

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

/**
 * Serial write function.
 */
int func_write(const char *buf, int cnt)
{
    for (int i = 0; i < cnt; i++) {
        serial.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);
}

/************************* callback functions *******************************/

void cmd_cat(int argc, char **argv)
{
    if ( argc != 2 ) {
        printf("\rusage: cat <filename>\n");
        return;
    }
    mDot::mdot_file file = GLOBAL_mdot->openUserFile(argv[1], mDot::FM_RDONLY);
    if ( file.fd < 0 ) {
        printf("\rFailed to open %s\n", argv[1]);
        return;
    }
    char *data_buf = (char*) malloc(file.size);
    bool rc = GLOBAL_mdot->readUserFile(file, data_buf, file.size);
    if ( rc != true ) {
        printf("\rFailed to read %s\n", argv[1]);
        goto cleanup;
    }
    printf("%s\n", data_buf);

cleanup:
    free(data_buf);
    GLOBAL_mdot->closeUserFile(file);
}
/*****************************************************************************
 * Function:        cmd_help
 * Description:     displays the list of commands available
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
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");
}


/*****************************************************************************
 * 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[GLOBAL_mdot->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]);
    GLOBAL_mdot->setLogLevel(logLevel);
    printf("\r\n");
}

/*****************************************************************************
 * Function:        cmd_ls
 * Description:     list the user files on flash
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_ls(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    vector<mDot::mdot_file> userFiles;
    userFiles = GLOBAL_mdot->listUserFiles();
    vector<mDot::mdot_file>::iterator pos;

    for ( pos = userFiles.begin(); pos != userFiles.end(); ++pos ) {
        printf("\r  %-33s %d\n", pos->name, pos->size);
    }
    printf("\r\n");
}

/*****************************************************************************
 * Function:        cmd_ShowControls
 * Description:     show active controls
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_ShowControls(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    ConfigurationHandler_showControls();
    printf("\r\n");

}

/*****************************************************************************
 * Function:        cmd_reset
 * Description:     reset the cpu
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_reset(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    GLOBAL_mdot->resetCpu();
}

/*****************************************************************************
 * Function:        cmd_rm
 * Description:     removes a user file from flash
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_rm(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    if ( argc != 2 ) {
        printf("\rusage: rm <filename>\n");
        return;
    }
    if ( strcmp(argv[1], "*") == 0 ) {
        vector<mDot::mdot_file> userFiles;
        userFiles = GLOBAL_mdot->listUserFiles();
        vector<mDot::mdot_file>::iterator pos;
        for ( pos = userFiles.begin(); pos != userFiles.end(); ++pos ) {
            GLOBAL_mdot->deleteUserFile(pos->name);
        }
    } else {
        GLOBAL_mdot->deleteUserFile(argv[1]);
    }
}

/*****************************************************************************
 * Function:        cmd_create
 * Description:     create a control
 *
 * @param           argc-> number of args
 * @param           argv-> control name, control type
 * @return          none
 *****************************************************************************/
void cmd_create(int argc, char **argv)
{
    if ( argc != 3 ) {
        printf("\r\nusage: create [controlName] [controlType]\n");
        printf("\rcontrolType-> 0=timer, 1=PID, 2=setpoint, 3=composite, 4=manual\r\n");
        return;
    }
    // send a message to the configuration handler to create the control
    Message_t *msg  = MailBox.alloc();
    memset(msg, 0, sizeof(Message_t));
    msg->action  = ACTION_CREATE;
    msg->control = (Control_t) atoi(argv[2]);
    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);

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

/*****************************************************************************
 * Function:        cmd_destroy
 * Description:     reset the cpu
 *
 * @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 [controlName] [controlType]\n");
        printf("\rcontrolType-> 0=timer, 1=PID, 2=setpoint, 3=composite, 4=manual\r\n");
        return;
    }

    // send a message to the configuration handler to destroy the control
    Message_t *msg  = MailBox.alloc();
    memset(msg, 0, sizeof(Message_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);

    MailBox.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 != 7 ) {
        printf("\rusage: create-setpoint <filename> <id> <input> <output> <direction> <tolerance>\n");
        printf("\rexample: create-setpoint control_sp_1.json SPC_01 i_tra01 o_rly1 1 5\r\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[1024];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\", "
             "\"priority\":     \"800\","
             "\"input\":        \"%s\", "
             "\"output\":       \"%s\", "
             "\"setpoint\":     \"100\","
             "\"prodfact\":     \"100\","
             "\"actingDir\":    \"%s\", "
             "\"halert\":       \"115\","
             "\"lalert\":       \"85\", "
             "\"hfs\":          \"130\","
             "\"lfs\":          \"70\", "
             "\"tol\":          \"%s\"  }", argv[2], argv[3], argv[4], argv[5], argv[6]
            );

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

    // send a message to the configuration handler to create the control
    Message_t *msg  = MailBox.alloc();
    memset(msg, 0, sizeof(Message_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);

    MailBox.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 != 6 ) {
        printf("\rusage: create-timer <filename> <id> <output> <priority> <duration>\n");
        printf("\rexample: create-timer control_tm_1.json timer-1 o_rly1 750 60\n");
        printf("\r     <startTime> is epoch time\n");
        printf("\r     <duration>  is in seconds\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 time_buf[32];
    sprintf(time_buf, "%lu", time(NULL)+5);

    char data_buf[1024];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\", "
             "\"output\":       \"%s\", "
             "\"priority\":     \"%s\", "
             "\"starttime\":    \"%s\", "
             "\"duration\":     \"%s\", ", argv[2], argv[3], argv[4], time_buf, argv[5]
             );
            

    bool status = GLOBAL_mdot->saveUserFile(argv[1], (void *)data_buf, 1024);
    if( status != true ) {
        logInfo("(%d)save file failed, status=%d", __LINE__, status);
        return;
    }
    
    // send a message to the configuration handler to create the control
    Message_t *msg  = MailBox.alloc();
    memset(msg, 0, sizeof(Message_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);

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

}

/*****************************************************************************
 * 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)
{
    if ( argc != 5 ) {
        printf("\rusage:   create-manual <filename> <id> <output> <state>\n");
        printf("\rexample: create-manual control_mn_1.json man-1 o_rly1 1\r\n");
        return;
    }

    char data_buf[1024];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\",  "
             "\"output\":       \"%s\",  "
             "\"type\":         \"1\",   "
             "\"priority\":     \"100\", "
             "\"duration\":     \"0\",   "
             "\"setpoint\":     \"0\",   "
             "\"state\":        \"%d\",  "
             "\"percent\":      \"100\"  }", argv[2], argv[3], atoi(argv[4])
            );

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

    // send a message to the configuration handler to create the control
    Message_t *msg  = MailBox.alloc();
    memset(msg, 0, sizeof(Message_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);

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

/*****************************************************************************
 * 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 != 3 ) {
        printf("\rusage: cif <filename> <input>\r\n");
        printf("\rexampe: cif input_i_tra01.json i_tra01\n");
        return;
    }

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

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

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

/*****************************************************************************
 * Function:        cmd_cmf
 * Description:     create manual control file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_cmf(int argc, char **argv)
{
    if ( argc != 2 ) {
        printf("\rusage: cmf <filename> <relay\r\n");
        printf("\rexmaple: cmd control_mn_1.json o_rly1");
        return;
    }

    char data_buf[1024];
    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":           \"%s\", "
             "\"type\":         \"1\", "
             "\"priority\":     \"100\", "
             "\"duration\":     \"30\", "       // seconds
             "\"setpoint\":     \"2000.0\", "
             "\"state\":        \"1\", "
             "\"percent\":      \"100\", }", argv[2]
            );

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


/*****************************************************************************
 * Function:        cmd_cof
 * Description:     create output file
 *
 * @param           argc-> number of args
 * @param           argv-> filename
 * @return          none
 *****************************************************************************/
void cmd_cof(int argc, char **argv)
{
    if ( argc != 5 ) {
        printf("\rusage: cof <filename> <output> <name> <reg>\r\n");
        printf("\rexample: cof output_rly1.json o_rly1 Relay1 1\r\n");
        return;
    }

    char data_buf[1024];

    snprintf(data_buf, sizeof(data_buf),
             "{ "
             "\"id\":       \"%s\", "
             "\"name\":     \"%s\", "
             "\"units\":    \"\", "
             "\"min\":      \"0\", "
             "\"max\":      \"300\", "
             "\"node\":     \"0\", "
             "\"reg\":      \"%s\", "
             "\"rtype\":    \"1\", "
             "\"type\":     \"16\", "
             "\"size\":     \"2\", "
             "\"order\":    \"2\", "
             "\"fmt\":      \"%%.2f\", "
             "\"rfreq\":    \"5\", "
             "\"toperiod\": \"0\", "
             "\"scalelo\":  \"0\", "
             "\"scalehi\":  \"100\" }", argv[2], argv[3], argv[4]);

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

    // send a message to the modbust master
    logInfo("Sending mail to ModbusMasterMailBox, filename=%s", argv[1]);
    Message_t *modbus_mail = ModbusMasterMailBox.alloc();
    modbus_mail->action = ACTION_READ_FILE;
    strncpy( modbus_mail->controlFile, argv[1], (sizeof(modbus_mail->controlFile)-1));
    ModbusMasterMailBox.put(modbus_mail);

    // send a message to the output master
    logInfo("Sending mail to OutputMaster, filename = %s", argv[1]);
    OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc();
    output_mail->action = ACTION_NEW;
    strncpy(output_mail->controlFile, argv[1], sizeof(output_mail->controlFile)-1);
    OutputMasterMailBox.put(output_mail);
}

/*****************************************************************************
 * Function:        cmd_heap
 * Description:     display heap statistics
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_heap(int argc, char **argv)
{
    UNUSED(argc), UNUSED(argv);
    __heapstats((__heapprt)fprintf,stderr);   // print initial free heap size
}

/*****************************************************************************
 * Function:        cmd_modify
 * Description:     modify an active control
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_modify(int argc, char **argv)
{
    // stubbed
    printf("\rNot yet implemented.\n");
    return;
}

/*****************************************************************************
 * Function:        cmd_stats
 * Description:     display mDot stats
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_stats(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    mDot::mdot_stats stats = GLOBAL_mdot->getStats();

    printf("\r                        Up: %u\n", stats.Up);
    printf("\r                      Down: %u\n", stats.Down);
    printf("\r                     Joins: %u\n", stats.Joins);
    printf("\r                 JoinFails: %u\n", stats.JoinFails);
    printf("\r                MissedAcks: %u\n", stats.MissedAcks);
    printf("\r                 CRCErrors: %u\n", stats.CRCErrors);
    printf("\r\n");
    printf("\r                 Freq band: %u\n", GLOBAL_mdot->getFrequencyBand());
    printf("\r              Freq subband: %u\n", GLOBAL_mdot->getFrequencySubBand());
    printf("\r         Session data rate: %u\n", GLOBAL_mdot->getSessionDataRate());
    printf("\r       Public Network Mode: %s\n", GLOBAL_mdot->getPublicNetwork() ? "yes" : "no");
    printf("\r   Application device port: %u\n", GLOBAL_mdot->getAppPort());
    printf("\r                     Class: %s\n", GLOBAL_mdot->getClass().c_str());
    printf("\r         Max packet length: %u\n", GLOBAL_mdot->getMaxPacketLength());
    std::vector<uint8_t> na = GLOBAL_mdot->getNetworkAddress();
    std::string str(na.begin(), na.end());
    printf("\r           Network address: %s\n", str.c_str());
    printf("\r              Network name: %s\n", GLOBAL_mdot->getNetworkName().c_str());
    std::vector<uint8_t> nid = GLOBAL_mdot->getNetworkId();
    std::string networkIdStr(nid.begin(), nid.end());
    printf("\r                Network ID: %s\n", networkIdStr.c_str());
    printf("\r          Join byter order: %s\n", GLOBAL_mdot->getJoinByteOrder() == 0 ? "LSB" : "MSB");
    printf("\r              Join retries: %u\n", GLOBAL_mdot->getJoinRetries());
    printf("\r                 Join mode: %u\n", GLOBAL_mdot->getJoinMode());
    printf("\r       Network join status: %s\n", GLOBAL_mdot->getNetworkJoinStatus() ? "yes" : "no");
    printf("\r           Link fail count: %u\n", GLOBAL_mdot->getLinkFailCount());
    printf("\r   Packets Tx'd to gateway: %u\n", GLOBAL_mdot->getUpLinkCounter());
    printf("\r Packets Rx'd from gateway: %u\n", GLOBAL_mdot->getDownLinkCounter());
    printf("\r            AES encryption: %s\n", GLOBAL_mdot->getAesEncryption() ? "enabled" : "disabled");
    printf("\r              Tx data rate: %u\n", GLOBAL_mdot->getTxDataRate());
    printf("\r          Datarate Details: %s\n", GLOBAL_mdot->getDateRateDetails(GLOBAL_mdot->getTxDataRate()).c_str());
    printf("\r                  Tx power: %u\n", GLOBAL_mdot->getTxPower());
    printf("\r              Antenna gain: %u\n", GLOBAL_mdot->getAntennaGain());
    printf("\r             Min frequency: %u\n", GLOBAL_mdot->getMinFrequency());
    printf("\r             Max frequency: %u\n", GLOBAL_mdot->getMaxFrequency());
    printf("\r               CRC enabled: %s\n", GLOBAL_mdot->getCrc() ? "yes" : "no");
    printf("\r               ACK enabled: %s\n", GLOBAL_mdot->getAck() ? "yes" : "no");

    printf("\r\n");
}

/*****************************************************************************
 * Function:        cmd_resetStats
 * Description:     resets the mDot stats
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_resetStats(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    GLOBAL_mdot->resetStats();
}

/*****************************************************************************
 * Function:        cmd_rssiStats
 * Description:     displays mDot RSSI statistics
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_rssiStats(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);

    mDot::rssi_stats s = GLOBAL_mdot->getRssiStats();

    printf("\r     Last: %d dB\n", s.last);
    printf("\r      Min: %d dB\n", s.min);
    printf("\r      Max: %d dB\n", s.max);
    printf("\r      Avg: %d dB\n", s.avg);

    printf("\r\n");
}

/*****************************************************************************
 * Function:        cmd_snrStats
 * Description:     displays signal-to-noise ratio stats
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
void cmd_snrStats(int argc, char **argv)
{
    mDot::snr_stats s = GLOBAL_mdot->getSnrStats();

    printf("\r     Last: %d cB\n", s.last);
    printf("\r      Min: %d cB\n", s.min);
    printf("\r      Max: %d cB\n", s.max);
    printf("\r      Avg: %d cB\n", s.avg);

    printf("\r\n");
}

/*****************************************************************************
 * Function:        cmd_stack
 * Description:     display thread stack statisics
 *
 * @param           argc (not used)
 * @param           argv (not used)
 * @return          none
 *****************************************************************************/
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)"BLEHandler",       GLOBAL_BLE_thread));
    taskList.push_back(make_pair((string)"CloudDataHandler", GLOBAL_CDH_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 = %u/%u/%u/%u\tpri=%-8u 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");
}

/*****************************************************************************
 * 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=%s, name=%s, units=%s, node=%d, reg=%d, size=%d, order=%d, value=%2.2f\r\n", iter->first.c_str(), iter->second.name.c_str(), iter->second.units.c_str(), iter->second.node, iter->second.reg, iter->second.size, iter->second.order, value.value );
    }
}

/*****************************************************************************
 * Function:        cmd_time
 * Description:     display real-time clock
 ****************************************************************************/
void cmd_time(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    
    time_t rawtime;
    time(&rawtime);
    
    int iyr=0, imo=0, idy=0, ihr=0, imn=0, isc=0;
    rtc_get_time(&iyr, &imo, &idy, &ihr, &imn, &isc);
    printf("RTC time: %04d-%02d-%02d %02d:%02d:%02d\r\n", iyr, imo, idy, ihr, imn, isc);
    printf("\repoch timestamp: %lu\r\n", time(NULL));
}

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

    DisplayOutputs();
}

/*****************************************************************************
 * Function:        cmd_sout
 * Description:     set output
 *
 * @param           argc-> number of args
 * @param           argv-> output
 * @return          none
 *****************************************************************************/
void cmd_sout(int argc, char **argv)
{
    float value = atof( argv[2] );

    if ( argc != 3 ) {
        printf("\rusage: sout <output> <value>\r\n");
        printf("\rexample: sout o_rly1 1\r\n");
        return;
    }
    ModbusMasterWriteRegister( argv[1], value );
}

/*****************************************************************************
 * 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 2016 12 25 12 0 0\r\n");
        return;
    }

    rtc_set_time(atoi(argv[1]),     // year
                 atoi(argv[2]),     // month
                 atoi(argv[3]),     // day
                 atoi(argv[4]),     // hr
                 atoi(argv[5]),     // min
                 atoi(argv[6]));    // sec
}

/*****************************************************************************
 * Function:        cmd_simin
 * Description:     simulat input
 *
 * @param           argc-> number of args
 * @param           argv-> input
 * @return          none
 *****************************************************************************/
void cmd_simin(int argc, char **argv)
{
    float value = atof( argv[2] );

    if ( argc < 3 ) {
        printf("\rusage: simin <input> <value> <low> <hi> <step>\r\n");
        printf("\rexample: simin i_tra01 100 90 110 5\r\n");
        return;
    }

    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;
        return;
    }
    SimulateInputMap[argv[1]].min = atof(argv[3]);
    SimulateInputMap[argv[1]].max = atof(argv[4]);
    SimulateInputMap[argv[1]].step = atof(argv[5]);

}

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

    char logString[LOG_BYTES_PER_ENTRY];

    LogLocalApi_PopEntry( logString );
    if( logString[0] != '\0' ) {
        printf("%s\r\n", logString );
    } else {
        printf("%s\r\n", "No String Found" );
    }
}

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

    std::string logString = "This is a string to log";

    LogLocalApi_PushEntry( logString.c_str() );
}

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

    EventReasonStruct_t eventReason;
    eventReason.eventReason = EVENT_REASON_AUTO;
    eventReason.inputValue = 100.00;
    strncpy(eventReason.inputTag, "i_stub01", sizeof(eventReason.inputTag) );
    eventReason.outputValue = 0.0;
    strncpy(eventReason.outputTag, "o_stub01", sizeof(eventReason.outputTag) );
    EventLoggerApi( eventReason );
}