AT Command Set mDot firmware with updated libmDot, to fix endian problem with joining LoRaWAN network

Dependencies:   MTS-Serial libmDot mbed-rtos mbed-src

Fork of mDot_AT_firmware by MultiTech

Files at this revision

API Documentation at this revision

Comitter:
Mike Fiore
Date:
Thu Jun 25 10:23:41 2015 -0500
Parent:
0:e2b8246361bc
Child:
2:e5eebd74d36d
Commit message:
update debug, add command source files

Changed in this revision

CommandTerminal/CmdACKAttempts.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdACKAttempts.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAdaptiveDataRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAdaptiveDataRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAttention.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAttention.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdCRC.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdCRC.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataPending.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataPending.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataSessionKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataSessionKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDebugBaudRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDebugBaudRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeviceId.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeviceId.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayConfig.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayConfig.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayStats.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayStats.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDummy.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDummy.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdEncryption.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdEncryption.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdErrorCorrection.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdErrorCorrection.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFactoryDefault.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFactoryDefault.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencyBand.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencyBand.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencySubBand.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencySubBand.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdIdentification.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdIdentification.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdJoinRequest.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdJoinRequest.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdJoinRetries.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdJoinRetries.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLinkCheckCount.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLinkCheckCount.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLinkCheckThreshold.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLinkCheckThreshold.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLogLevel.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdLogLevel.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkAddress.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkAddress.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkId.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkId.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinMode.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinMode.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinStatus.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinStatus.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkLinkCheck.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkLinkCheck.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkSessionKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkSessionKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPing.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPing.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPublicNetwork.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPublicNetwork.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdReceiveContinuous.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdReceiveContinuous.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdReceiveOnce.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdReceiveOnce.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdResetCpu.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdResetCpu.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRssi.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRssi.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxDataRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxDataRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxFrequency.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxFrequency.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxInverted.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxInverted.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxOutput.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdRxOutput.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSaveConfig.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSaveConfig.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendBinary.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendBinary.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendString.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendString.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendStringHighBW.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendStringHighBW.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendStringOnInterval.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSendStringOnInterval.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialBaudRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialBaudRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialReceiveTimeout.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialReceiveTimeout.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialWakeDelay.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialWakeDelay.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialWakeInterval.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSerialWakeInterval.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSnr.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSnr.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdStartUpMode.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdStartUpMode.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTimeOnAir.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTimeOnAir.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxChannel.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxChannel.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxDataRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxDataRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxFrequency.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxFrequency.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxInverted.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxInverted.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxNextMs.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxNextMs.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxPower.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxPower.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxWait.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxWait.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Command.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Command.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CommandTerminal.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CommandTerminal.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Commands.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Test/TestCommandTerminal.h Show annotated file Show diff for this revision Revisions of this file
debug.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
version.h Show annotated file Show diff for this revision Revisions of this file
wakeup.c Show annotated file Show diff for this revision Revisions of this file
wakeup.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdACKAttempts.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdACKAttempts.h"
+
+CmdACKAttempts::CmdACKAttempts(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Require ACK", "AT+ACK", "Enable to require send acknowledgement (0: off, N: number of attempts until ACK recevied)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-8)";
+    _queryable = true;
+}
+
+uint32_t CmdACKAttempts::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("ACK Attempts: ");
+
+        _serial.writef("%u\r\n", _dot->getAck());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t retries;
+        sscanf(args[1].c_str(), "%lu", &retries);
+
+        if ((code = _dot->setAck(retries)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdACKAttempts::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t retries;
+        if (sscanf(args[1].c_str(), "%lu", &retries) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (retries > 8) {
+            setErrorMessage("Invalid attempts, expects (0-8)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdACKAttempts.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDACKATTEMPTS_H__
+#define __CMDACKATTEMPTS_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdACKAttempts : public Command {
+
+public:
+
+    CmdACKAttempts(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDACKATTEMPTS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAdaptiveDataRate.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,53 @@
+#include "CmdAdaptiveDataRate.h"
+
+
+CmdAdaptiveDataRate::CmdAdaptiveDataRate(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Adaptive Data Rate", "AT+ADR", "Enable/disable Adaptive Data Rate (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdAdaptiveDataRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Adaptive Data Rate: ");
+
+        _serial.writef("%d\r\n", _dot->getAdr());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+        if ((code = _dot->setAdr(enable)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdAdaptiveDataRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAdaptiveDataRate.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDCMDADAPTIVEDATARATE_H__
+#define __CMDCMDADAPTIVEDATARATE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdAdaptiveDataRate : public Command {
+
+public:
+
+    CmdAdaptiveDataRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDCMDADAPTIVEDATARATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAttention.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,16 @@
+#include "CmdAttention.h"
+
+CmdAttention::CmdAttention(mDot* dot) : Command(dot, "Attention", "AT", "Attention") 
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+CmdAttention::CmdAttention(mDot* dot, const char* name, const char* text, const char* desc) : Command(dot, name, text, desc)
+{
+    
+}
+
+uint32_t CmdAttention::action(std::vector<std::string> args) {
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAttention.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+#ifndef __CMDATTENTION_H__
+#define __CMDATTENTION_H__
+
+#include "Command.h"
+
+class CmdAttention : public Command {
+
+public:
+
+    CmdAttention(mDot* dot);   
+    CmdAttention(mDot* dot, const char* name, const char* text, const char* desc);
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:
+};
+
+#endif // __CMDATTENTION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdCRC.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,52 @@
+#include "CmdCRC.h"
+
+CmdCRC::CmdCRC(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "CRC Checking ", "AT+CRC", "Enable/disable CRC checking of received packets. (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdCRC::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("CRC Check: ");
+
+        _serial.writef("%d\r\n", _dot->getCrc());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+        if ((code = _dot->setCrc(enable)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdCRC::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdCRC.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDCRC_H__
+#define __CMDCRC_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdCRC : public Command {
+
+public:
+
+    CmdCRC(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDCRC_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataPending.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+#include "CmdDataPending.h"
+
+CmdDataPending::CmdDataPending(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Data Pending", "AT+DP", "Indicator of data in queue on server"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdDataPending::action(std::vector<std::string> args)
+{
+    if (_dot->getVerbose())
+        _serial.writef("Data Pending: ");
+
+    _serial.writef("%d\r\n", _dot->getDataPending());
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataPending.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+
+#ifndef __CMDDATAPENDING_H__
+#define __CMDDATAPENDING_H__
+
+#include "Command.h"
+
+class CmdDataPending : public Command {
+
+public:
+
+    CmdDataPending(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDATAPENDING_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataSessionKey.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,56 @@
+#include "CmdDataSessionKey.h"
+
+CmdDataSessionKey::CmdDataSessionKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Data Session Key", "AT+DSK", "Data session encryption key (16 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:16)";
+    _queryable = true;
+}
+
+uint32_t CmdDataSessionKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Data Session Key: ");
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDataSessionKey(), ".").c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        std::vector<uint8_t> NewKey;
+
+        // Read in the key components...
+        readByteArray(args[1], NewKey, KEY_LENGTH);
+
+        if ((code = _dot->setDataSessionKey(NewKey)) == mDot::MDOT_OK) {
+            _serial.writef("Set Data Session Key: ");
+            _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdDataSessionKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataSessionKey.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDDATASESSIONKEY_H__
+#define __CMDDATASESSIONKEY_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdDataSessionKey : public Command {
+
+public:
+
+    CmdDataSessionKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDATASESSIONKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDebugBaudRate.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,57 @@
+#include "CmdDebugBaudRate.h"
+
+CmdDebugBaudRate::CmdDebugBaudRate(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Debug Baud Rate", "AT+DIPR", "Set debug serial baud rate, default: 115200 "), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2400,4800,9600,19200,38400,57600,115200,230400,460800,921600)";
+    _queryable = true;
+}
+
+uint32_t CmdDebugBaudRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Debug Baud Rate: ");
+
+        _serial.writef("%lu\r\n", _dot->getDebugBaud());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t baudrate = 0;
+
+        sscanf(args[1].c_str(), "%lu", &baudrate);
+
+        if ((code = _dot->setDebugBaud(baudrate)) == mDot::MDOT_OK) {
+            _serial.writef("Set Debug Baud Rate: %lu\r\n", baudrate);
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdDebugBaudRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        uint32_t baudrate;
+
+        if (sscanf(args[1].c_str(), "%lu", &baudrate) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDebugBaudRate.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+#ifndef __CMDDEBUGBAUDRATE_H__
+#define __CMDDEBUGBAUDRATE_H__
+
+#include "Command.h"
+
+class CmdDebugBaudRate : public Command {
+
+public:
+
+    CmdDebugBaudRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDEBUGBAUDRATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeviceId.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,31 @@
+#include "CmdDeviceId.h"
+#include <algorithm>
+
+CmdDeviceId::CmdDeviceId(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Device ID", "AT+DI", "Device EUI (unique, set at factory) (8 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:8)";
+    _queryable = true;
+}
+
+uint32_t CmdDeviceId::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDeviceId(), ":").c_str());
+    }
+
+    return 0;
+}
+
+bool CmdDeviceId::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeviceId.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+#ifndef __CMDDEVICEID_H__
+#define __CMDDEVICEID_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdDeviceId : public Command {
+
+public:
+
+    CmdDeviceId(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDEVICEID_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayConfig.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,101 @@
+#include "CmdDisplayConfig.h"
+
+CmdDisplayConfig::CmdDisplayConfig(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Display Settings", "AT&V", "Displays current settings and status"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "TABLE";
+}
+
+uint32_t CmdDisplayConfig::action(std::vector<std::string> args) {
+    _serial.writef("Device ID:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDeviceId(), ":").c_str());
+
+    _serial.writef("Frequency Band:\t\t%s\r\n", mDot::FrequencyBandStr(_dot->getFrequencyBand()).c_str());
+    _serial.writef("Frequency Sub Band:\t%u\r\n", _dot->getFrequencySubBand());
+
+    _serial.writef("Public Network:\t\t%s\r\n", _dot->getPublicNetwork() ? "on" : "off");
+    _serial.writef("Start Up Mode:\t\t%s\r\n", mDot::ModeStr(_dot->getStartUpMode()).c_str());
+
+    _serial.writef("Network Address:\t%s\r\n", mts::Text::bin2hexString(_dot->getNetworkAddress()).c_str());
+
+    _serial.writef("Network ID:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkId(), ":").c_str());
+
+    _serial.writef("Network ID Passphrase:\t%s\r\n", _dot->getNetworkName().c_str());
+
+    _serial.writef("Network Key:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkKey(), ".").c_str());
+
+    _serial.writef("Network Key Passphrase:\t%s\r\n", _dot->getNetworkPassphrase().c_str());
+
+    _serial.writef("Network Session Key:\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkSessionKey(), ".").c_str());
+
+    _serial.writef("Data Session Key:\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDataSessionKey(), ".").c_str());
+
+    _serial.writef("Network Join Mode:\t%s\r\n", mDot::JoinModeStr(_dot->getJoinMode()).c_str());
+
+    _serial.writef("Network Join Retries:\t%u\r\n", _dot->getJoinRetries());
+
+    _serial.writef("Link Check Threshold:\t");
+    if (_dot->getLinkCheckThreshold() == 0) {
+        _serial.writef("off\r\n");
+    } else {
+        _serial.writef("%lu\r\n", _dot->getLinkCheckThreshold());
+    }
+
+    _serial.writef("Link Check Count:\t");
+    if (_dot->getLinkCheckCount() == 0) {
+        _serial.writef("off\r\n");
+    } else {
+        _serial.writef("%lu packets\r\n", _dot->getLinkCheckCount());
+    }
+
+    _serial.writef("Error Correction:\t");
+    if (_dot->getFec() == 0) {
+        _serial.writef("off\r\n");
+    } else {
+        _serial.writef("%u bytes\r\n", _dot->getFec());
+    }
+
+    _serial.writef("ACK Retries:\t\t");
+    if (_dot->getAck() == 0) {
+        _serial.writef("off\r\n");
+    } else {
+        _serial.writef("%u\r\n", _dot->getAck());
+    }
+
+    _serial.writef("Encryption:\t\t%s\r\n", _dot->getAesEncryption() ? "on" : "off");
+    _serial.writef("CRC:\t\t\t%s\r\n", _dot->getCrc() ? "on" : "off");
+    _serial.writef("Adaptive Data Rate:\t%s\r\n", _dot->getAdr() ? "on" : "off");
+    _serial.writef("Command Echo:\t\t%s\r\n", _dot->getEcho() ? "on" : "off");
+    _serial.writef("Verbose Response:\t%s\r\n", _dot->getVerbose() ? "on" : "off");
+
+    _serial.writef("Tx Frequency:\t\t%lu\r\n", _dot->getTxFrequency());
+    _serial.writef("Tx Data Rate:\t\t%s\r\n", mDot::DataRateStr(_dot->getTxDataRate()).c_str());
+    _serial.writef("Tx Power:\t\t%u\r\n", _dot->getTxPower());
+    _serial.writef("Tx Wait:\t\t%s\r\n", _dot->getTxWait() ? "on" : "off");
+
+    _serial.writef("Tx Inverted Signal:\t%s\r\n", _dot->getTxInverted() ? "on" : "off");
+
+    _serial.writef("Rx Frequency:\t\t%lu\r\n", _dot->getRxFrequency());
+    _serial.writef("Rx Data Rate:\t\t%s\r\n", mDot::DataRateStr(_dot->getRxDataRate()).c_str());
+    _serial.writef("Rx Inverted Signal:\t%s\r\n", _dot->getRxInverted() ? "on" : "off");
+
+    _serial.writef("Rx Output Style:\t%s\r\n", mDot::RxOutputStr(_dot->getRxOutput()).c_str());
+
+    _serial.writef("Debug Baud Rate:\t%lu\r\n", _dot->getDebugBaud());
+    _serial.writef("Serial Baud Rate:\t%lu\r\n", _dot->getBaud());
+
+    _serial.writef("Serial Wake Interval:\t%lu s\r\n", _dot->getSerialWakeInterval());
+    _serial.writef("Serial Wake Delay:\t%lu ms\r\n", _dot->getSerialWakeDelay());
+    _serial.writef("Serial Receive Timeout:\t%u ms\r\n", _dot->getSerialReceiveTimeout());
+
+    _serial.writef("Log Level:\t\t%ld\r\n", _dot->getLogLevel());
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayConfig.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+#ifndef __CMDDISPLAYCONFIG_H__
+#define __CMDDISPLAYCONFIG_H__
+
+#include "Command.h"
+
+class CmdDisplayConfig : public Command {
+
+public:
+
+    CmdDisplayConfig(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+
+    mts::MTSSerial& _serial;
+
+};
+
+#endif // __CMDDISPLAYCONFIG_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayStats.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,23 @@
+#include "CmdDisplayStats.h"
+
+CmdDisplayStats::CmdDisplayStats(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Display Stats", "AT&S", "Display statistics"),
+  _serial(serial), _dot(dot) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "TABLE";
+}
+
+uint32_t CmdDisplayStats::action(std::vector<std::string> args) {
+
+    mDot::mdot_stats stats = _dot->getStats();
+
+    _serial.writef("Join Attempts:  %5lu\r\n", stats.Joins);
+    _serial.writef("Join Fails:     %5lu\r\n", stats.JoinFails);
+    _serial.writef("Up Packets:     %5lu\r\n", stats.Up);
+    _serial.writef("Down Packets:   %5lu\r\n", stats.Down);
+    _serial.writef("Missed Acks:    %5lu\r\n", stats.MissedAcks);
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayStats.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDDISPLAYSTATS_H__
+#define __CMDDISPLAYSTATS_H__
+
+#include "Command.h"
+
+class CmdDisplayStats : public Command {
+
+public:
+
+    CmdDisplayStats(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+
+    mts::MTSSerial& _serial;
+    mDot* _dot;
+
+};
+
+#endif // __CMDDISPLAYSTATS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDummy.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,13 @@
+#include "CmdDummy.h"
+
+CmdDummy::CmdDummy(mDot* dot, const char* name, const char* txt, const char* dsc) : Command(dot, name, txt, dsc)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdDummy::action(std::vector<std::string> args)
+{
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDummy.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,16 @@
+#ifndef __CMDDUMMY_H__
+#define __CMDDUMMY_H__
+
+#include "Command.h"
+
+class CmdDummy : public Command {
+
+public:
+
+    CmdDummy(mDot* dot, const char* name, const char* text, const char* desc);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CMDDUMMY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdEncryption.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,53 @@
+#include "CmdEncryption.h"
+
+CmdEncryption::CmdEncryption(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "AES Encryption", "AT+ENC", "Enable/disable AES encryption (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdEncryption::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Encryption: ");
+
+        _serial.writef("%d\r\n", _dot->getAesEncryption());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+
+        if ((code = _dot->setAesEncryption(enable)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdEncryption::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdEncryption.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDENCRYPTION_H__
+#define __CMDENCRYPTION_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdEncryption : public Command {
+
+public:
+
+    CmdEncryption(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDENCRYPTION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdErrorCorrection.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,61 @@
+#include "CmdErrorCorrection.h"
+
+CmdErrorCorrection::CmdErrorCorrection(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Error Correction", "AT+FEC", "Configure Forward Error Correction bytes (1 to 4)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(1-4)";
+    _queryable = true;
+}
+
+uint32_t CmdErrorCorrection::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Error Correction Bytes: ");
+
+        _serial.writef("%u\r\n", _dot->getFec());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t bytes;
+        sscanf(args[1].c_str(), "%lu", &bytes);
+
+        if ((code = _dot->setFec(bytes)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdErrorCorrection::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t retries;
+        if (sscanf(args[1].c_str(), "%u", &retries) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (retries < 1 || retries > 4)
+        {
+            setErrorMessage("Invalid bytes, expects (1-4)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdErrorCorrection.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDERRORCORRECTION_H__
+#define __CMDERRORCORRECTION_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdErrorCorrection : public Command {
+
+public:
+
+    CmdErrorCorrection(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDERRORCORRECTION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFactoryDefault.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,15 @@
+#include "CmdFactoryDefault.h"
+
+CmdFactoryDefault::CmdFactoryDefault(mDot* dot) : Command(dot, "Reset Factory Defaults", "AT&F", "Reset current configuration to factory defaults")
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdFactoryDefault::action(std::vector<std::string> args)
+{
+    _dot->resetConfig();
+    _dot->resetNetworkSession();
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFactoryDefault.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,16 @@
+#ifndef __CmdFactoryDefault_H__
+#define __CmdFactoryDefault_H__
+
+#include "Command.h"
+
+class CmdFactoryDefault : public Command {
+
+public:
+
+    CmdFactoryDefault(mDot* dot);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CmdFactoryDefault_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencyBand.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,31 @@
+#include "CmdFrequencyBand.h"
+
+CmdFrequencyBand::CmdFrequencyBand(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Frequency Band", "AT+FREQ", "Configured Frequency Band '868' or '915'"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(868,915)";
+    _queryable = true;
+}
+
+uint32_t CmdFrequencyBand::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Frequency Band: ");
+
+        _serial.writef("%s\r\n", mDot::FrequencyBandStr(_dot->getFrequencyBand()).c_str());
+    }
+
+    return 0;
+}
+
+bool CmdFrequencyBand::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencyBand.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+#ifndef __CMDFREQUENCYBAND_H__
+#define __CMDFREQUENCYBAND_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdFrequencyBand : public Command {
+
+public:
+
+    CmdFrequencyBand(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDFREQUENCYBAND_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencySubBand.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdFrequencySubBand.h"
+
+CmdFrequencySubBand::CmdFrequencySubBand(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Frequency Sub-band", "AT+FSB", "Set the frequency sub-band for US 915, (0:ALL, 1-8)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-8)";
+    _queryable = true;
+}
+
+uint32_t CmdFrequencySubBand::action(std::vector<std::string> args)
+{
+
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Frequency Sub Band: ");
+
+        _serial.writef("%u\r\n", _dot->getFrequencySubBand());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t band;
+        sscanf(args[1].c_str(), "%lu", &band);
+
+        if ((code = _dot->setFrequencySubBand(band)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdFrequencySubBand::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t band;
+        if (sscanf(args[1].c_str(), "%u", &band) != 1) {
+            setErrorMessage("Invalid arguments");
+            return false;
+        }
+
+        if (band < mDot::FSB_ALL || band > mDot::FSB_8) {
+            setErrorMessage("Invalid channel band, expects (0-8)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencySubBand.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDFREQUENCYSUBBAND_H__
+#define __CMDFREQUENCYSUBBAND_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdFrequencySubBand : public Command {
+
+public:
+
+    CmdFrequencySubBand(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDFREQUENCYSUBBAND_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdIdentification.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+#include "CmdIdentification.h"
+#include "version.h"
+
+CmdIdentification::CmdIdentification(mDot* dot, mts::MTSSerial& serial) : Command(dot, "Request Id", "ATI", "Request Identification"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdIdentification::action(std::vector<std::string> args)
+{
+    std::string version = AT_APPLICATION_VERSION;
+
+    _serial.writef("MultiTech mDot\r\n");
+    _serial.writef("Firmware: %s\r\n", version.c_str());
+    _serial.writef("Library : %s\r\n", _dot->getId().c_str());
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdIdentification.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+#ifndef __CMDIDENTIFICATION_H__
+#define __CMDIDENTIFICATION_H__
+
+#include "Command.h"
+
+class CmdIdentification : public Command {
+
+public:
+
+    CmdIdentification(mDot* dot, mts::MTSSerial& serial);   
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDIDENTIFICATION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdJoinRequest.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,39 @@
+#include "CmdJoinRequest.h"
+#include "CommandTerminal.h"
+
+CmdJoinRequest::CmdJoinRequest(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Join Network", "AT+JOIN", "Join network, provide argument of '1' to force join (acquire network address and session keys)"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(force:1)";
+}
+
+uint32_t CmdJoinRequest::action(std::vector<std::string> args) {
+    int32_t code;
+    std::string buf;
+    char ch;
+
+    if (args.size() > 1 && args[1] == "1")
+        _dot->resetNetworkSession();
+
+    code = _dot->joinNetworkOnce();
+
+    if (code == mDot::MDOT_OK) {
+        _serial.writef("Successfully joined network\r\n");
+        return 0;
+    } else {
+        std::string error = mDot::getReturnCodeString(code)  + " - " + _dot->getLastError();
+        setErrorMessage(error);
+    }
+
+    return 1;
+}
+
+bool CmdJoinRequest::verify(std::vector<std::string> args) {
+    if (args.size() == 1 || (args.size() == 2 && args[1] == "1"))
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdJoinRequest.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+#ifndef __CMDJOINREQUEST_H__
+#define __CMDJOINREQUEST_H__
+
+#include "Command.h"
+
+class CmdJoinRequest : public Command {
+
+public:
+
+    CmdJoinRequest(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDJOINREQUEST_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdJoinRetries.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,51 @@
+#include "CmdJoinRetries.h"
+
+CmdJoinRetries::CmdJoinRetries(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Join Retries", "AT+JR", "Number of times to retry joining the network in an attempt (0 - 255)"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-255)";
+    _queryable = true;
+}
+
+uint32_t CmdJoinRetries::action(std::vector<std::string> args) {
+    if (args.size() == 1) {
+        if (_dot->getVerbose())
+            _serial.writef("Join Retries: ");
+
+        _serial.writef("%u\r\n", _dot->getJoinRetries());
+    } else if (args.size() == 2) {
+        int32_t code;
+        uint32_t retries;
+        sscanf(args[1].c_str(), "%lu", &retries);
+
+        if ((code = _dot->setJoinRetries(retries)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+bool CmdJoinRetries::verify(std::vector<std::string> args) {
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+
+        uint32_t retries;
+        if (sscanf(args[1].c_str(), "%lu", &retries) == 1) {
+            if (retries > 255) {
+                setErrorMessage("Invalid retries, expects (0-255)");
+                return false;
+            }
+            return true;
+        }
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdJoinRetries.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+#ifndef __CMDJOINRETRIES_H_
+#define __CMDJOINRETRIES_H_
+
+#include "Command.h"
+
+class CmdJoinRetries : public Command {
+
+public:
+
+    CmdJoinRetries(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDJOINRETRIES_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLinkCheckCount.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdLinkCheckCount.h"
+
+CmdLinkCheckCount::CmdLinkCheckCount(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Link Check Count", "AT+LCC", "Set number of packets between each link check if ACK's are disabled"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0:off,N:Packets (max 255))";
+    _queryable = true;
+}
+
+uint32_t CmdLinkCheckCount::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Link Check Count: ");
+
+        _serial.writef("%u\r\n", _dot->getLinkCheckCount());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t count;
+        sscanf(args[1].c_str(), "%lu", &count);
+
+        if ((code = _dot->setLinkCheckCount(count)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdLinkCheckCount::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t count;
+        if (sscanf(args[1].c_str(), "%u", &count) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (count > 255) {
+            setErrorMessage("Invalid count, expects (0:off,N:Packets (max 255))");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLinkCheckCount.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDLINKCHECKCOUNT_H__
+#define __CMDLINKCHECKCOUNT_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdLinkCheckCount : public Command {
+
+public:
+
+    CmdLinkCheckCount(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDLINKCHECKCOUNT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLinkCheckThreshold.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,57 @@
+#include "CmdLinkCheckThreshold.h"
+
+CmdLinkCheckThreshold::CmdLinkCheckThreshold(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Link Check Threshold", "AT+LCT", "Set threshold for number of link check of ACK failures to tolerate, (0: off, N: number of failures"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-255)";
+    _queryable = true;
+}
+
+uint32_t CmdLinkCheckThreshold::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Link Check Threshold: ");
+
+        _serial.writef("%u\r\n", _dot->getLinkCheckThreshold());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t count;
+        sscanf(args[1].c_str(), "%lu", &count);
+
+        if ((code = _dot->setLinkCheckThreshold(count)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdLinkCheckThreshold::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t count;
+        sscanf(args[1].c_str(), "%lu", &count);
+
+        if (count > 255) {
+            setErrorMessage("Invalid count, expects (0-255))");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLinkCheckThreshold.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDLINKCHECKHTHRESHOLD_H__
+#define __CMDLINKCHECKHTHRESHOLD_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdLinkCheckThreshold : public Command {
+
+public:
+
+    CmdLinkCheckThreshold(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDLINKCHECKHTHRESHOLD_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLogLevel.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdLogLevel.h"
+
+CmdLogLevel::CmdLogLevel(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Debug Log Level", "AT+LOG", "Enable/disable debug logging. (0: off, 1:Fatal - 6:Trace)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-6)";
+    _queryable = true;
+}
+
+uint32_t CmdLogLevel::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Log Level: ");
+
+        _serial.writef("%u\r\n", _dot->getLogLevel());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        int32_t level;
+        sscanf(args[1].c_str(), "%ld", &level);
+
+        if ((code = _dot->setLogLevel(level)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdLogLevel::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        int32_t level;
+        if (sscanf(args[1].c_str(), "%ld", &level) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (level < 0 || level > 6) {
+            setErrorMessage("Invalid level, expects (0-6)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdLogLevel.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDLOGLEVEL_H__
+#define __CMDLOGLEVEL_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdLogLevel : public Command {
+
+public:
+
+    CmdLogLevel(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDLOGLEVEL_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkAddress.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,72 @@
+#include "CmdNetworkAddress.h"
+#include <algorithm>
+
+CmdNetworkAddress::CmdNetworkAddress(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Network Address", "AT+NA", "Network address (devAddr in LoraMac) (4 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:4)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkAddress::action(std::vector<std::string> args)
+{
+    std::vector<uint8_t> addr;
+
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Address: ");
+
+        addr = _dot->getNetworkAddress();
+
+        _serial.writef("%02x:%02x:%02x:%02x\r\n", addr[0], addr[1], addr[2], addr[3]);
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t temp;
+        uint32_t step = 2;
+
+        if (args[1].find(":") != std::string::npos || args[1].find(".") != std::string::npos || args[1].find("-") != std::string::npos)
+            step = 3;
+
+        // Convert the ASCII hex data to binary...
+        for (size_t i = 0; i < args[1].size(); i += step) 
+        {
+            sscanf(&args[1][i], "%02x", &temp);
+            addr.push_back(temp);
+        }
+
+        if ((code = _dot->setNetworkAddress(addr)) == mDot::MDOT_OK) {
+            _serial.writef("Set Network Address: ");
+            _serial.writef("%02x:%02x:%02x:%02x\r\n", addr[0], addr[1], addr[2], addr[3]);
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkAddress::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1) {
+        return true;
+    }
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 4))
+        {
+            setErrorMessage("Invalid address, expects (hex:4)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkAddress.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDNETWORKADDRESS_H__
+#define __CMDNETWORKADDRESS_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkAddress : public Command {
+
+public:
+
+    CmdNetworkAddress(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKADDRESS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkId.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,110 @@
+#include "CmdNetworkId.h"
+
+CmdNetworkId::CmdNetworkId(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network ID", "AT+NI", "Configured Network EUI/Name (App EUI in LoraMac) AT+NI=0,hex AT+NI=1,network_name  (Net ID = crc64(network_name)) (8 bytes)"),
+            _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,(hex:8)),(1,(string:128))";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkId::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network ID: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkId(), ":").c_str());
+
+        if (!_dot->getNetworkName().empty())
+            _serial.writef("Passphrase: '%s'\r\n", _dot->getNetworkName().c_str());
+    }
+    else
+    {
+        int32_t code;
+
+        if (args[1].find("1") == 0 && args[1].size() == 1)
+        {
+            std::string text;
+            if (args.size() > 3)
+            {
+                // passphrase was split on commas
+                for (size_t i = 2; i < args.size(); i++)
+                {
+                    text.append(args[i]);
+                    if (i < args.size() - 1)
+                        text.append(",");
+                }
+            }
+            else
+            {
+                text = args[2];
+            }
+
+            if ((code = _dot->setNetworkName(text)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Name: ");
+                _serial.writef("%s\r\n", text.c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+
+        }
+        else
+        {
+            std::vector<uint8_t> NewKey;
+            readByteArray(args[2], NewKey, EUI_LENGTH);
+            if ((code = _dot->setNetworkId(NewKey)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network ID: ");
+                _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkId::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 3) {
+        if (args[1] != "0" && args[1] != "1") {
+            setErrorMessage("Invalid type, expects (0,1)");
+            return false;
+        }
+        if (args[1] == "0" && !isHexString(args[2], 8)) {
+            setErrorMessage("Invalid ID, expects (hex:8");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() < 8) {
+            setErrorMessage("Invalid name, expects minimum 8 characters");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() > 128) {
+            setErrorMessage("Invalid name, expects (string:128)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkId.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDNETWORKID_H__
+#define __CMDNETWORKID_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkId : public Command {
+
+public:
+
+    CmdNetworkId(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKID_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinMode.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,55 @@
+#include "CmdNetworkJoinMode.h"
+
+CmdNetworkJoinMode::CmdNetworkJoinMode(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Network Join Mode", "AT+NJM", "0: Manual configuration, 1: OTA Network Join, 2: Auto OTA Network Join on start up (default: 1)"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-2)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkJoinMode::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%u\r\n", _dot->getJoinMode());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t mode = (args[1] == "1") ? 1 : 0;
+        mode = (args[1] == "2" ? 2 : mode);
+        if ((code = _dot->setJoinMode(mode)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkJoinMode::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (!(args[1] == "0" || args[1] == "1" || args[1] == "2"))
+        {
+            setErrorMessage("Invalid parameter, expects (0: Manual, 1: OTA, 2: Auto OTA)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinMode.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDNETWORKJOINMODE_H__
+#define __CMDNETWORKJOINMODE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkJoinMode : public Command {
+
+public:
+
+    CmdNetworkJoinMode(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKJOINMODE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinStatus.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#include "CmdNetworkJoinStatus.h"
+
+CmdNetworkJoinStatus::CmdNetworkJoinStatus(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network Join Status", "AT+NJS", "0: Not joined, 1: Joined"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkJoinStatus::action(std::vector<std::string> args)
+{
+    if (_dot->getVerbose())
+        _serial.writef("%s: ", name());
+
+    _serial.writef("%u\r\n", _dot->getNetworkJoinStatus());
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinStatus.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+#ifndef __CMDNETWORKJOINSTATUS_H__
+#define __CMDNETWORKJOINSTATUS_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkJoinStatus : public Command {
+
+public:
+
+    CmdNetworkJoinStatus(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKJOINSTATUS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkKey.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,110 @@
+#include "CmdNetworkKey.h"
+
+CmdNetworkKey::CmdNetworkKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network Key", "AT+NK", "Configured network key/passphrase (App Key in LoraMac) ##  AT+NK=0,hex  AT+NK=1,passphrase (Net key = cmac(passphrase)) (16 bytes)"),
+    _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,(hex:16)),(1,(string:128))";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Key: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkKey(), ".").c_str());
+        if (!_dot->getNetworkPassphrase().empty())
+            _serial.writef("Passphrase: '%s'\r\n", _dot->getNetworkPassphrase().c_str());
+
+    }
+    else if (args.size() == 3)
+    {
+        int32_t code;
+
+        if (args[1].find("1") == 0 && args[1].size() == 1)
+        {
+            std::string text;
+            if (args.size() > 3)
+            {
+                // passphrase was split on commas
+                for (size_t i = 2; i < args.size(); i++)
+                {
+                    text.append(args[i]);
+                    if (i < args.size() - 1)
+                        text.append(",");
+                }
+            }
+            else
+            {
+                text = args[2];
+            }
+
+            if ((code = _dot->setNetworkPassphrase(text)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Passphrase: ");
+                _serial.writef("%s\r\n", text.c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+        else
+        {
+            std::vector<uint8_t> NewKey;
+            readByteArray(args[2], NewKey, KEY_LENGTH);
+            if ((code = _dot->setNetworkKey(NewKey)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Key: ");
+                _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 3) {
+        if (args[1] != "0" && args[1] != "1") {
+            setErrorMessage("Invalid type, expects (0,1)");
+            return false;
+        }
+        if (args[1] == "0" && !isHexString(args[2], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() < 8) {
+            setErrorMessage("Invalid name, expects minimum 8 characters");
+            return false;
+        }
+
+        if (args[1] == "1" && (args[2].size() > 128 || args[2].size() < 8)) {
+            setErrorMessage("Invalid passphrase, expects (string:8-128)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkKey.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,22 @@
+
+#ifndef __CMDNETWORKKEY_H__
+#define __CMDNETWORKKEY_H__
+
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkKey : public Command {
+
+public:
+
+    CmdNetworkKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkLinkCheck.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,32 @@
+#include "CmdNetworkLinkCheck.h"
+#include "CommandTerminal.h"
+
+CmdNetworkLinkCheck::CmdNetworkLinkCheck(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Network Link Check", "AT+NLC", "Perform network link check, displays dBm above floor, number of gateways in range and optional packet payload if received"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(-20.0-20.0),(1-)";
+}
+
+uint32_t CmdNetworkLinkCheck::action(std::vector<std::string> args) {
+    mDot::link_check lc;
+
+    lc = _dot->networkLinkCheck();
+    if (lc.status) {
+        if (_dot->getVerbose())
+            _serial.writef("%s:", name());
+
+        _serial.writef("%d,%lu\r\n", lc.dBm, lc.gateways);
+
+        if (!lc.payload.empty())
+            _serial.writef("%s\r\n", CommandTerminal::formatPacketData(lc.payload, _dot->getRxOutput()).c_str());
+
+    } else {
+        setErrorMessage(_dot->getLastError());
+        return 1;
+    }
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkLinkCheck.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+#ifndef __CMDNETWORKLINKCHECK_H__
+#define __CMDNETWORKLINKCHECK_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkLinkCheck : public Command {
+
+public:
+
+    CmdNetworkLinkCheck(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKLINKCHECK_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkSessionKey.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,57 @@
+#include "CmdNetworkSessionKey.h"
+
+CmdNetworkSessionKey::CmdNetworkSessionKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network Session Key", "AT+NSK", "Network session encryption key (16 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:16)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkSessionKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Session Key: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkSessionKey(), ".").c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        std::vector<uint8_t> NewKey;
+
+        // Read in the key components...
+        readByteArray(args[1], NewKey, KEY_LENGTH);
+
+        if ((code = _dot->setNetworkSessionKey(NewKey)) == mDot::MDOT_OK) {
+            _serial.writef("Set Network Session Key: ");
+            _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkSessionKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkSessionKey.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDNETWORKSESSIONKEY_H__
+#define __CMDNETWORKSESSIONKEY_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdNetworkSessionKey : public Command {
+
+public:
+
+    CmdNetworkSessionKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKSESSIONKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPing.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,27 @@
+#include "CmdPing.h"
+
+CmdPing::CmdPing(mDot* dot, mts::MTSSerial& serial) : Command(dot, "Send Ping", "AT+PING", "Sends ping and displays the servers received rssi and snr"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(-140-0),(-20.0-20.0)";
+}
+
+uint32_t CmdPing::action(std::vector<std::string> args)
+{
+    mDot::ping_response response;
+    response = _dot->ping();
+    if (response.status != mDot::MDOT_OK) {
+        std::string error = mDot::getReturnCodeString(response.status);
+
+        if (response.status != mDot::MDOT_NOT_JOINED)
+            error +=  + " - " + _dot->getLastError();
+
+        setErrorMessage(error);
+        return 1;
+    }
+
+    _serial.writef("%d,%d.%d\r\n", response.rssi, response.snr / 10, abs(response.snr) % 10);
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPing.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+
+#ifndef __CMDPING_H__
+#define __CMDPING_H__
+
+#include "Command.h"
+
+class CmdPing : public Command {
+
+public:
+
+    CmdPing(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDPING_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPublicNetwork.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,52 @@
+#include "CmdPublicNetwork.h"
+
+CmdPublicNetwork::CmdPublicNetwork(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Public Network", "AT+PN", "Enable/disable public network mode. (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdPublicNetwork::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%d\r\n", _dot->getPublicNetwork());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+
+        if ((code = _dot->setPublicNetwork(enable)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdPublicNetwork::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPublicNetwork.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+#ifndef __CMDPUBLICNETWORK_H__
+#define __CMDPUBLICNETWORK_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdPublicNetwork : public Command {
+
+public:
+
+    CmdPublicNetwork(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDPUBLICNETWORK_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdReceiveContinuous.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,51 @@
+#include "CmdReceiveContinuous.h"
+#include "CommandTerminal.h"
+
+CmdReceiveContinuous::CmdReceiveContinuous(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Receive Continuous", "AT+RECVC", "Continuously receive and display packets. (escape sequence: +++)"),
+    _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "in: (2000-2147483647) ms; out: (string:242) or (hex:242)";
+}
+
+uint32_t CmdReceiveContinuous::action(std::vector<std::string> args)
+{
+    std::vector<uint8_t> data;
+
+    std::string escape_buffer;
+    char ch;
+
+    while (true)
+    {
+        if (_dot->recv(data) == mDot::MDOT_OK) {
+            if (_dot->getVerbose())
+                _serial.writef("Packet data:\r\n");
+            _serial.writef("%s\r\n", CommandTerminal::formatPacketData(data, _dot->getRxOutput()).c_str());
+
+            data.clear();
+        }
+
+        while (_serial.readable()) {
+            _serial.read(&ch, 1);
+            escape_buffer += ch;
+            if (escape_buffer == CommandTerminal::escape_sequence)
+                return 0;
+
+            osDelay(50);
+        }
+
+        escape_buffer.clear();
+    }
+
+    return 0;
+}
+
+bool CmdReceiveContinuous::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdReceiveContinuous.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDRECEIVECONTINUOUS_H__
+#define __CMDRECEIVECONTINUOUS_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdReceiveContinuous : public Command {
+
+public:
+
+    CmdReceiveContinuous(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:    
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRECEIVECONTINUOUS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdReceiveOnce.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,33 @@
+#include "CmdReceiveOnce.h"
+#include "CommandTerminal.h"
+
+CmdReceiveOnce::CmdReceiveOnce(mDot* dot, mts::MTSSerial& serial) : Command(dot, "Receive Once", "AT+RECV", "Receive and display one packet."),
+    _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(string:242) or (hex:242)";
+}
+
+uint32_t CmdReceiveOnce::action(std::vector<std::string> args)
+{
+    std::vector<uint8_t> data;
+
+    if (_dot->recv(data) == mDot::MDOT_OK) {
+        if (_dot->getVerbose())
+            _serial.writef("Packet data:\r\n");
+
+        if (!data.empty())
+            _serial.writef("%s\r\n", CommandTerminal::formatPacketData(data, _dot->getRxOutput()).c_str());
+    }
+
+    return 0;
+}
+
+bool CmdReceiveOnce::verify(std::vector<std::string> args)
+{
+	if (args.size() == 1)
+		return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdReceiveOnce.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDRECEIVEONCE_H__
+#define __CMDRECEIVEONCE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdReceiveOnce : public Command {
+
+public:
+
+    CmdReceiveOnce(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:    
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRECEIVEONCE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdResetCpu.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,15 @@
+#include "CmdResetCpu.h"
+
+CmdResetCpu::CmdResetCpu(mDot* dot, mts::MTSSerial& serial) : Command(dot, "Reset CPU", "ATZ", "Reset the CPU"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdResetCpu::action(std::vector<std::string> args) 
+{
+    _serial.writef("\r\nOK\r\n");
+    wait(0.5);
+    HAL_NVIC_SystemReset();
+    return 0; 
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdResetCpu.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+
+#ifndef __CMDRESETCPU_H__
+#define __CMDRESETCPU_H__
+
+#include "Command.h"
+
+class CmdResetCpu : public Command {
+
+public:
+
+    CmdResetCpu(mDot* dot, mts::MTSSerial& serial);   
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial _serial;
+
+};
+
+#endif // __CMDRESETCPU_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRssi.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,23 @@
+#include "CmdRssi.h"
+
+CmdRssi::CmdRssi(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Signal Strength", "AT+RSSI", "Displays signal strength information for received packets: last, min, max, avg"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(-140-0),(-140-0),(-140-0),(-140-0)";
+    _queryable = true;
+}
+
+uint32_t CmdRssi::action(std::vector<std::string> args)
+{
+    mDot::rssi_stats stats = _dot->getRssiStats();
+
+    if (_dot->getVerbose())
+        _serial.writef("RSSI stats: ");
+
+    _serial.writef("%d, %d, %d, %d\r\n", stats.last, stats.min, stats.max, stats.avg);
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRssi.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+#ifndef __CMDRSSI_H__
+#define __CMDRSSI_H__
+
+#include "Command.h"
+
+class CmdRssi : public Command {
+
+public:
+
+    CmdRssi(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRSSI_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxDataRate.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,89 @@
+#include "CmdRxDataRate.h"
+
+CmdRxDataRate::CmdRxDataRate(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Rx Data Rate", "AT+RXDR", "Set the Rx data rate"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    if (_dot->getFrequencyBand() == mDot::FB_915) 
+        _usage = "(7-10)";
+    else
+        _usage = "(7-12)";
+
+    _queryable = true;
+}
+
+uint32_t CmdRxDataRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Rx Data Rate: ");
+
+        _serial.writef("%s\r\n", mDot::DataRateStr(_dot->getRxDataRate()).c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t datarate = 0;
+        uint8_t i;
+
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if ((code = _dot->setRxDataRate(datarate)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdRxDataRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint8_t i;
+        int datarate = -1;
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if (datarate < 0)
+        { 
+            if (_dot->getFrequencyBand() == mDot::FB_915) 
+                setErrorMessage("Invalid data rate, expects (7-10)");
+            else
+                setErrorMessage("Invalid data rate, expects (7-12)");
+            return false;
+        }
+
+        if (_dot->getFrequencyBand() == mDot::FB_915) {
+            if (datarate < 2) {
+                setErrorMessage("Invalid data rate, expects (7-10)");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxDataRate.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDRXDATARATE_H__
+#define __CMDRXDATARATE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdRxDataRate : public Command {
+
+public:
+
+    CmdRxDataRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRXDATARATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxFrequency.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,68 @@
+#include "CmdRxFrequency.h"
+
+CmdRxFrequency::CmdRxFrequency(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Rx Frequency", "AT+RXF", "Set the Rx frequency for +RECV,+RECVC"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    if (_dot->getFrequencyBand() == mDot::FB_868)
+        _usage = "(0,863000000-870000000)";
+    else
+        _usage = "(0,902000000-928000000)";
+    _queryable = true;
+}
+
+uint32_t CmdRxFrequency::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Rx Frequency: ");
+
+        _serial.writef("%lu\r\n", _dot->getRxFrequency());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t frequency = 0;
+        sscanf(args[1].c_str(), "%lu", &frequency);
+        if ((code = _dot->setRxFrequency(frequency)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdRxFrequency::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t frequency;
+        if (sscanf(args[1].c_str(), "%lu", &frequency) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        DEBUG_PRINTF("FREQ MIN: %lu MAX: %lu\r\n", _dot->getMinFrequency(), _dot->getMaxFrequency());
+
+        if (frequency != 0 && (frequency < _dot->getMinFrequency() || frequency > _dot->getMaxFrequency())) {
+            if (_dot->getFrequencyBand() == mDot::FB_868)
+                setErrorMessage("Invalid timeout, expects (0,863000000-870000000)"); 
+            else
+                setErrorMessage("Invalid timeout, expects (0,902000000-928000000)");
+
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxFrequency.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDRXFREQUENCY_H__
+#define __CMDRXFREQUENCY_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdRxFrequency : public Command {
+
+public:
+
+    CmdRxFrequency(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRXFREQUENCY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxInverted.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,52 @@
+#include "CmdRxInverted.h"
+
+CmdRxInverted::CmdRxInverted(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Set Rx inverted", "AT+RXI", "Set Rx signal inverted, (default:on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdRxInverted::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Rx Inverted: ");
+
+        _serial.writef("%d\r\n", _dot->getRxInverted());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool invert = args[1] == "1";
+        if ((code = _dot->setRxInverted(invert)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdRxInverted::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (!(args[1] == "0" || args[1] == "1")) {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxInverted.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDRXINVERTED_H__
+#define __CMDRXINVERTED_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdRxInverted : public Command {
+
+public:
+
+    CmdRxInverted(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRXINVERTED_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxOutput.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,52 @@
+#include "CmdRxOutput.h"
+
+CmdRxOutput::CmdRxOutput(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Rx Output", "AT+RXO", "Set the Rx output type (0:hexadecimal, 1:raw)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdRxOutput::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Rx Output: ");
+
+        _serial.writef("%u\r\n", _dot->getRxOutput());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t output = args[1] == "0" ? 0 : 1;
+        if ((code = _dot->setRxOutput(output)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdRxOutput::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (!(args[1] == "0" || args[1] == "1")) {
+            setErrorMessage("Invalid type, expects (0:hexadecimal, 1:raw)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdRxOutput.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDRXOUTPUT_H__
+#define __CMDRXOUTPUT_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdRxOutput : public Command {
+
+public:
+
+    CmdRxOutput(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDRXOUTPUT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSaveConfig.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+#include "CmdSaveConfig.h"
+
+CmdSaveConfig::CmdSaveConfig(mDot* dot) : Command(dot, "Save Configuration", "AT&W", "Save configuration to flash memory")
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdSaveConfig::action(std::vector<std::string> args)
+{
+    if (!_dot->saveConfig()) {
+      setErrorMessage("Failed to save to flash");
+      return 1;
+    }
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSaveConfig.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+
+#ifndef __CmdSaveConfig_H__
+#define __CmdSaveConfig_H__
+
+#include "Command.h"
+
+class CmdSaveConfig : public Command {
+
+public:
+
+    CmdSaveConfig(mDot* dot);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CmdSaveConfig_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendBinary.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdSendBinary.h"
+#include "CommandTerminal.h"
+
+CmdSendBinary::CmdSendBinary(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Send Binary", "AT+SENDB", "Sends supplied binary (hex) packet data one time and return response"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:242)";
+}
+
+uint32_t CmdSendBinary::action(std::vector<std::string> args) {
+    std::vector<uint8_t> data;
+    int32_t code;
+    uint8_t temp;
+    uint32_t length = args[1].size();
+
+    // Convert the ASCII hex data to binary...
+    for (uint32_t i = 0; i < length; i += 2) {
+        sscanf(&args[1][i], "%2x", &temp);
+        data.push_back(temp);
+    }
+
+    if ((code = _dot->send(data, _dot->getTxWait())) != mDot::MDOT_OK) {
+        std::string error = mDot::getReturnCodeString(code);
+
+        if (code != mDot::MDOT_NOT_JOINED)
+            error +=  + " - " + _dot->getLastError();
+
+        setErrorMessage(error);
+        return 1;
+    }
+
+    data.clear();
+
+    if (_dot->getTxWait() && _dot->recv(data) == mDot::MDOT_OK) {
+        if (!data.empty()) {
+            if (_dot->getVerbose())
+                _serial.writef("Packet data:\r\n");
+            _serial.writef("%s\r\n", CommandTerminal::formatPacketData(data, _dot->getRxOutput()).c_str());
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSendBinary::verify(std::vector<std::string> args) {
+    if (args.size() == 2) {
+        if (args[1].size() > 484 || !isHexString(args[1], args[1].size() / 2)) {
+            setErrorMessage("Invalid hex string, (hex:242)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendBinary.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+
+#ifndef __CMDSENDBINARY_H__
+#define __CMDSENDBINARY_H__
+
+#include "Command.h"
+
+class CmdSendBinary : public Command {
+
+public:
+
+    CmdSendBinary(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSENDBINARY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendString.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,66 @@
+#include "CmdSendString.h"
+#include "CommandTerminal.h"
+
+CmdSendString::CmdSendString(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Send Once", "AT+SEND", "Sends supplied packet data one time and return response, (max:242 bytes)"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(string:242)";
+}
+
+uint32_t CmdSendString::action(std::vector<std::string> args) {
+    // Argument had been split on each comma, rebuild payload
+    int32_t code;
+    std::string text;
+    for (size_t i = 1; i < args.size(); i++) {
+        text.append(args[i]);
+        if (i != args.size() - 1)
+            text.append(",");
+    }
+
+    std::vector<uint8_t> data(text.begin(), text.end());
+    if ((code = _dot->send(data, _dot->getTxWait())) != mDot::MDOT_OK) {
+        std::string error = mDot::getReturnCodeString(code);
+
+        if (code != mDot::MDOT_NOT_JOINED)
+            error +=  + " - " + _dot->getLastError();
+
+        setErrorMessage(error);
+        return 1;
+    }
+
+    if (_dot->getTxWait()) {
+        data.clear();
+
+        if (_dot->recv(data) == mDot::MDOT_OK) {
+            if (!data.empty()) {
+                if (_dot->getVerbose())
+                    _serial.writef("Packet data:\r\n");
+                _serial.writef("%s\r\n", CommandTerminal::formatPacketData(data, _dot->getRxOutput()).c_str());
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSendString::verify(std::vector<std::string> args) {
+
+    if (args.size() == 1) {
+        // allow sending empty packet to retrieve downstream messages
+        return true;
+    }
+
+    if (args.size() == 2) {
+        if (args[1].size() > 242) {
+            setErrorMessage("Invalid packet, expects (string:242)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendString.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+
+#ifndef __CMDSENDSTRING_H__
+#define __CMDSENDSTRING_H__
+
+#include "Command.h"
+
+class CmdSendString : public Command {
+
+public:
+
+    CmdSendString(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSENDSTRING_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendStringHighBW.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,58 @@
+#include "CmdSendStringHighBW.h"
+#include "CommandTerminal.h"
+
+CmdSendStringHighBW::CmdSendStringHighBW(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Send Once High BW", "AT+SENDH", "Sends supplied packet data one time and return response using High Bandwidth channel, (max:242 bytes)"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(string:242)";
+}
+
+uint32_t CmdSendStringHighBW::action(std::vector<std::string> args) {
+    // Argument had been split on each comma, rebuild payload
+    int32_t code;
+    std::string text;
+    for (size_t i = 1; i < args.size(); i++) {
+        text.append(args[i]);
+        if (i != args.size() - 1)
+            text.append(",");
+    }
+
+    std::vector<uint8_t> data(text.begin(), text.end());
+    if ((code = _dot->send(data, _dot->getTxWait(), true)) != mDot::MDOT_OK) {
+        std::string error = mDot::getReturnCodeString(code);
+
+        if (code != mDot::MDOT_NOT_JOINED)
+            error +=  + " - " + _dot->getLastError();
+
+        setErrorMessage(error);
+        return 1;
+    }
+
+    data.clear();
+
+    if (_dot->getTxWait() && _dot->recv(data) == mDot::MDOT_OK) {
+        if (!data.empty()) {
+            if (_dot->getVerbose())
+                _serial.writef("Packet data:\r\n");
+            _serial.writef("%s\r\n", CommandTerminal::formatPacketData(data, _dot->getRxOutput()).c_str());
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSendStringHighBW::verify(std::vector<std::string> args) {
+    if (args.size() == 2) {
+        if (args[1].size() > 242) {
+            setErrorMessage("Invalid packet, expects (string:242)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendStringHighBW.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+
+#ifndef __CMDSENDSTRINGHIGHBW_H__
+#define __CMDSENDSTRINGHIGHBW_H__
+
+#include "Command.h"
+
+class CmdSendStringHighBW : public Command {
+
+public:
+
+    CmdSendStringHighBW(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSENDSTRINGHIGHBW_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendStringOnInterval.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,108 @@
+#include "CmdSendStringOnInterval.h"
+#include "CommandTerminal.h"
+
+CmdSendStringOnInterval::CmdSendStringOnInterval(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Send Continuous", "AT+SENDI", "Sends supplied packet data on interval between sends, output any recevied packets (escape sequence: +++)"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(100-2147483647) ms,(string:242)";
+}
+
+uint32_t CmdSendStringOnInterval::action(std::vector<std::string> args) {
+    int32_t code;
+    uint32_t interval;
+    std::vector<uint8_t> data(args[2].begin(), args[2].end());
+
+    sscanf(args[1].c_str(), "%lu", &interval);
+
+    while (true) {
+        if (_dot->getJoinMode() == mDot::AUTO_OTA) {
+            Timer timer;
+            timer.start();
+            uint32_t backoff = 2000;
+            while (!_dot->getNetworkJoinStatus()) {
+                _serial.writef("Joining network... ");
+                if (_dot->joinNetworkOnce() == mDot::MDOT_OK) {
+                    _serial.writef("Network Joined\r\n");
+                } else {
+                    _serial.writef("Join failed\r\n");
+                }
+
+                if (CommandTerminal::waitForEscape(backoff)) {
+                    return 0;
+                }
+
+                if (backoff < 60 * 60 * 1000) {
+                    backoff *= 2;
+                }
+            }
+        } else if (!_dot->getNetworkJoinStatus()) {
+            setErrorMessage(mDot::getReturnCodeString(mDot::MDOT_NOT_JOINED));
+            return 1;
+        }
+
+        if ((code = _dot->send(data, _dot->getTxWait())) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code);
+
+            if (code != mDot::MDOT_NOT_JOINED)
+                error +=  + " - " + _dot->getLastError();
+
+            if (code == mDot::MDOT_INVALID_PARAM) {
+                setErrorMessage(error);
+                return 1;
+            } else {
+                _serial.writef("%s\r\n", error.c_str());
+            }
+        }
+
+        if (code == mDot::MDOT_OK) {
+            if (CommandTerminal::waitForEscape(3000, _dot, CommandTerminal::WAIT_SEND)) {
+                return 0;
+            }
+
+            if (_dot->getTxWait() || _dot->getAck() > 0) {
+                std::vector<uint8_t> rx_data;
+
+                if (_dot->recv(rx_data) == mDot::MDOT_OK) {
+                    if (!rx_data.empty()) {
+                        if (_dot->getVerbose())
+                            _serial.writef("Packet data:\r\n");
+                        _serial.writef("%s\r\n", CommandTerminal::formatPacketData(rx_data, _dot->getRxOutput()).c_str());
+                    }
+                }
+            }
+        }
+
+        if (CommandTerminal::waitForEscape(interval)) {
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSendStringOnInterval::verify(std::vector<std::string> args) {
+    if (args.size() == 3) {
+        uint32_t interval;
+        if (sscanf(args[1].c_str(), "%lu", &interval) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (interval < 100 || interval > INT_MAX) {
+            setErrorMessage("Invalid interval, expects (100-2147483647) ms");
+            return false;
+        }
+
+        if (args[2].size() > 242) {
+            setErrorMessage("Invalid packet, expects (string:242)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSendStringOnInterval.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+
+#ifndef __CMDSENDSTRINGONINTERVAL_H__
+#define __CMDSENDSTRINGONINTERVAL_H__
+
+#include "Command.h"
+
+class CmdSendStringOnInterval : public Command {
+
+public:
+
+    CmdSendStringOnInterval(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+
+};
+
+#endif // __CMDSENDSTRINGONINTERVAL_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialBaudRate.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,57 @@
+#include "CmdSerialBaudRate.h"
+
+CmdSerialBaudRate::CmdSerialBaudRate(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Serial Baud Rate", "AT+IPR", "Set serial baud rate, default: 115200 "), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2400,4800,9600,19200,38400,57600,115200,230400,460800,921600)";
+    _queryable = true;
+}
+
+uint32_t CmdSerialBaudRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Serial Baud Rate: ");
+
+        _serial.writef("%lu\r\n", _dot->getBaud());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t baudrate = 0;
+
+        sscanf(args[1].c_str(), "%lu", &baudrate);
+
+        if ((code = _dot->setBaud(baudrate)) == mDot::MDOT_OK) {
+            _serial.writef("Set Serial Baud Rate: %lu\r\n", baudrate);
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSerialBaudRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        uint32_t baudrate;
+
+        if (sscanf(args[1].c_str(), "%lu", &baudrate) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialBaudRate.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,18 @@
+#ifndef __CMDSERIALBAUDRATE_H__
+#define __CMDSERIALBAUDRATE_H__
+
+#include "Command.h"
+
+class CmdSerialBaudRate : public Command {
+
+public:
+
+    CmdSerialBaudRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSERIALBAUDRATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialReceiveTimeout.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,59 @@
+#include "CmdSerialReceiveTimeout.h"
+
+CmdSerialReceiveTimeout::CmdSerialReceiveTimeout(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Serial Receive Timeout", "AT+SDTO", "Read serial data until timeout (milliseconds)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-65000) ms";
+    _queryable = true;
+}
+
+uint32_t CmdSerialReceiveTimeout::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%lu\r\n", _dot->getSerialReceiveTimeout());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t timeout;
+        sscanf(args[1].c_str(), "%lu", &timeout);
+
+        if ((code = _dot->setSerialReceiveTimeout(timeout)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSerialReceiveTimeout::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t timeout;
+        if (sscanf(args[1].c_str(), "%lu", &timeout) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (timeout < 0 || timeout > 65000) {
+            setErrorMessage("Invalid timeout, expects (0-65000) ms");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialReceiveTimeout.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDSERIALRECEIVETIMEOUT_H__
+#define __CMDSERIALRECEIVETIMEOUT_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdSerialReceiveTimeout : public Command {
+
+public:
+
+    CmdSerialReceiveTimeout(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSERIALRECEIVETIMEOUT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialWakeDelay.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,60 @@
+#include "CmdSerialWakeDelay.h"
+
+CmdSerialWakeDelay::CmdSerialWakeDelay(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Serial Wake Delay", "AT+SDWD", "Time to wait for data after wakeup signal  (milliseconds)"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-2147483647) ms";
+    _queryable = true;
+}
+
+uint32_t CmdSerialWakeDelay::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%lu\r\n", _dot->getSerialWakeDelay());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t delay;
+        sscanf(args[1].c_str(), "%lu", &delay);
+
+        if ((code = _dot->setSerialWakeDelay(delay)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSerialWakeDelay::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t delay;
+        if (sscanf(args[1].c_str(), "%lu", &delay) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (delay < 2 || delay > INT_MAX) {
+            setErrorMessage("Invalid delay, expects (2-2147483647) ms");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialWakeDelay.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDSERIALWAKEDELAY_H__
+#define __CMDSERIALWAKEDELAY_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdSerialWakeDelay : public Command {
+
+public:
+
+    CmdSerialWakeDelay(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSERIALWAKEDELAY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialWakeInterval.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,59 @@
+#include "CmdSerialWakeInterval.h"
+
+CmdSerialWakeInterval::CmdSerialWakeInterval(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Serial Wake Interval", "AT+SDWI", "Serial data wakeup interval to generate wake signal (seconds)"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-2147483647) s";
+    _queryable = true;
+}
+
+uint32_t CmdSerialWakeInterval::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%lu\r\n", _dot->getSerialWakeInterval());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t timeout;
+        sscanf(args[1].c_str(), "%lu", &timeout);
+
+        if ((code = _dot->setSerialWakeInterval(timeout)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdSerialWakeInterval::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+    
+    if (args.size() == 2) {
+        uint32_t timeout;
+        if (sscanf(args[1].c_str(), "%lu", &timeout) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (timeout < 2 || timeout > INT_MAX) {
+            setErrorMessage("Invalid interval, expects (2-2147483647) s");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSerialWakeInterval.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDSERIALWAKEINTERVAL_H__
+#define __CMDSERIALWAKEINTERVAL_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdSerialWakeInterval : public Command {
+
+public:
+
+    CmdSerialWakeInterval(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSERIALWAKEINTERVAL_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSnr.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,22 @@
+#include "CmdSnr.h"
+
+CmdSnr::CmdSnr(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Signal To Noise Ratio", "AT+SNR", "Display signal to noise ratio of received packets: last, min, max, avg"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(-20.0-20.0),(-20.0-20.0),(-20.0-20.0),(-20.0-20.0)";
+    _queryable = true;
+}
+
+uint32_t CmdSnr::action(std::vector<std::string> args)
+{
+    mDot::snr_stats stats = _dot->getSnrStats();
+
+    if (_dot->getVerbose())
+        _serial.writef("SNR stats: ");
+
+    _serial.writef("%d.%d, %d.%d, %d.%d, %d.%d\r\n", stats.last / 10, abs(stats.last % 10), stats.min / 10, abs(stats.min % 10), stats.max / 10, abs(stats.max % 10), stats.avg / 10, abs(stats.avg % 10));
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSnr.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,17 @@
+#ifndef __CMDSNR_H__
+#define __CMDSNR_H__
+
+#include "Command.h"
+
+class CmdSnr : public Command {
+
+public:
+
+    CmdSnr(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSNR_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdStartUpMode.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,54 @@
+#include "CmdStartUpMode.h"
+
+CmdStartUpMode::CmdStartUpMode(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Start Up Mode", "AT+SMODE", "0: AT command mode, 1: Serial data mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdStartUpMode::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%u\r\n", _dot->getStartUpMode());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t mode;
+
+        mode = (args[1] == "1") ? mDot::SERIAL_MODE : mDot::COMMAND_MODE;
+
+        if ((code = _dot->setStartUpMode(mode)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdStartUpMode::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: Command, 1: Serial Data)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdStartUpMode.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDSTARTUPMODE_H__
+#define __CMDSTARTUPMODE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdStartUpMode : public Command {
+
+public:
+
+    CmdStartUpMode(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDSTARTUPMODE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTimeOnAir.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,43 @@
+#include "CmdTimeOnAir.h"
+
+CmdTimeOnAir::CmdTimeOnAir(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Time on air", "AT+TOA", "Get time in ms of packet tx with current datarate"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-242)";
+    _queryable = true;
+}
+
+uint32_t CmdTimeOnAir::action(std::vector<std::string> args) {
+
+    if (_dot->getVerbose())
+        _serial.writef("Time on air: ");
+
+    uint16_t bytes;
+
+    sscanf(args[1].c_str(), "%hu", &bytes);
+
+    _serial.writef("%lu\r\n", _dot->getTimeOnAir(bytes + 13));
+
+    return 0;
+}
+
+bool CmdTimeOnAir::verify(std::vector<std::string> args) {
+
+    if (args.size() < 2) {
+        setErrorMessage("Invalid parameter, expects (0-242)");
+        return false;
+    }
+
+    uint16_t bytes;
+
+    sscanf(args[1].c_str(), "%hu", &bytes);
+
+    if (bytes > 242) {
+        setErrorMessage("Invalid parameter, expects (0-242)");
+        return false;
+    }
+
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTimeOnAir.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,22 @@
+#ifndef __CMDTIMEONAIR_H__
+#define __CMDTIMEONAIR_H__
+
+#include "Command.h"
+
+
+
+class CommandTerminal;
+
+class CmdTimeOnAir : public Command {
+
+public:
+
+    CmdTimeOnAir(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTIMEONAIR_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxChannel.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,33 @@
+#include "CmdTxChannel.h"
+
+CmdTxChannel::CmdTxChannel(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Tx Channels", "AT+TXCH", "List Tx channel frequencies for sub-band"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "TABLE";
+    _queryable = true;
+}
+
+uint32_t CmdTxChannel::action(std::vector<std::string> args) {
+    if (args.size() == 1) {
+        std::vector<uint32_t> channels = _dot->getChannels();
+
+        for (int i = 0; i < 8; i++) {
+            _serial.writef("%d: %d 125k\r\n", i, channels[i]);
+        }
+
+        if (_dot->getFrequencyBand() == mDot::FB_868) {
+            _serial.writef("D: %d 125k\r\n", channels[8]);
+        } else {
+            if (_dot->getVerbose())
+                _serial.writef("Tx Channels: \r\n");
+
+            _serial.writef("U: %d 500k\r\n", channels[8]);
+            _serial.writef("D: %d 500k\r\n", channels[9]);
+        }
+    }
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxChannel.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,19 @@
+#ifndef __CMDTXCHANNEL_H__
+#define __CMDTXCHANNEL_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxChannel : public Command {
+
+public:
+
+    CmdTxChannel(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXCHANNEL_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxDataRate.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,89 @@
+#include "CmdTxDataRate.h"
+
+CmdTxDataRate::CmdTxDataRate(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Tx Data Rate", "AT+TXDR", "Set the Tx data rate for all channels"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+
+    if (_dot->getFrequencyBand() == mDot::FB_915)
+        _usage = "(7-10)";
+    else
+        _usage = "(7-12)";
+    _queryable = true;
+}
+
+uint32_t CmdTxDataRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Data Rate: ");
+
+        _serial.writef("%s\r\n", mDot::DataRateStr(_dot->getTxDataRate()).c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t datarate = 0;
+        uint8_t i;
+
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if ((code = _dot->setTxDataRate(datarate)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxDataRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint8_t i;
+        int datarate = -1;
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if (datarate < 0)
+        {       
+            if (_dot->getFrequencyBand() == mDot::FB_915)
+                setErrorMessage("Invalid data rate, expects (7-10)");
+            else
+                setErrorMessage("Invalid data rate, expects (7-12)");
+            return false;
+        }   
+
+        if (_dot->getFrequencyBand() == mDot::FB_915) {
+            if (datarate < 2) {
+                setErrorMessage("Invalid data rate, expects (7-10)");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxDataRate.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDTXDATARATE_H__
+#define __CMDTXDATARATE_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxDataRate : public Command {
+
+public:
+
+    CmdTxDataRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXDATARATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxFrequency.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,69 @@
+#include "CmdTxFrequency.h"
+#include <climits>
+
+CmdTxFrequency::CmdTxFrequency(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Tx Frequency", "AT+TXF", "Set Tx frequency"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    if (_dot->getFrequencyBand() == mDot::FB_868)
+        _usage = "(0,863000000-870000000)";
+    else
+        _usage = "(0,902000000-928000000)";
+    _queryable = true;
+}
+
+uint32_t CmdTxFrequency::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Frequency: ");
+
+        _serial.writef("%lu\r\n", _dot->getTxFrequency());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t frequency = 0;
+
+        sscanf(args[1].c_str(), "%lu", &frequency);
+        if ((code = _dot->setTxFrequency(frequency)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxFrequency::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t frequency = ULONG_MAX;
+        if (sscanf(args[1].c_str(), "%lu", &frequency) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (frequency != 0 && (frequency < _dot->getMinFrequency() || frequency > _dot->getMaxFrequency())) {
+            if (_dot->getFrequencyBand() == mDot::FB_868)
+                setErrorMessage("Invalid frequency, expects (0,863000000-870000000)"); 
+            else
+                setErrorMessage("Invalid frequency, expects (0,902000000-928000000)");
+
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxFrequency.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDTXFREQUENCY_H__
+#define __CMDTXFREQUENCY_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxFrequency : public Command {
+
+public:
+
+    CmdTxFrequency(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXFREQUENCY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxInverted.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,53 @@
+#include "CmdTxInverted.h"
+
+CmdTxInverted::CmdTxInverted(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Set Tx inverted", "AT+TXI", "Set Tx signal inverted, (default:off)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdTxInverted::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Inverted: ");
+
+        _serial.writef("%d\r\n", _dot->getTxInverted());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool invert = args[1] == "1";
+        if ((code = _dot->setTxInverted(invert)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxInverted::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (!(args[1] == "0" || args[1] == "1")) {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxInverted.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,20 @@
+#ifndef __CMDTXINVERTED_H__
+#define __CMDTXINVERTED_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxInverted : public Command {
+
+public:
+
+    CmdTxInverted(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXINVERTED_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxNextMs.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,26 @@
+#include "CmdTxNextMs.h"
+
+CmdTxNextMs::CmdTxNextMs(mDot* dot, mts::MTSSerial& serial)
+: Command(dot, "Tx Next", "AT+TXN", "Get time in ms until next free channel"), _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-)";
+    _queryable = true;
+}
+
+uint32_t CmdTxNextMs::action(std::vector<std::string> args) {
+
+    if (_dot->getVerbose())
+        _serial.writef("Next Tx in: ");
+
+    _serial.writef("%lu\r\n", _dot->getNextTxMs());
+
+    return 0;
+}
+
+bool CmdTxNextMs::verify(std::vector<std::string> args) {
+
+    if (args.size() > 1)
+        return false;
+
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxNextMs.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,22 @@
+#ifndef __CMDTXNEXTMS_H__
+#define __CMDTXNEXTMS_H__
+
+#include "Command.h"
+
+
+
+class CommandTerminal;
+
+class CmdTxNextMs : public Command {
+
+public:
+
+    CmdTxNextMs(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXNEXTMS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxPower.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,62 @@
+#include "CmdTxPower.h"
+
+CmdTxPower::CmdTxPower(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Tx Power", "AT+TXP", "Set the Tx power for all channels"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-20)";
+    _queryable = true;
+}
+
+uint32_t CmdTxPower::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Power: ");
+
+        _serial.writef("%lu\r\n", _dot->getTxPower());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t power = 0;
+        sscanf(args[1].c_str(), "%lu", &power);
+
+        if ((code = _dot->setTxPower(power)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxPower::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t power = 0;
+        if (sscanf(args[1].c_str(), "%lu", &power) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (power < 2 || power > 20)
+        {
+            setErrorMessage("Invalid power, expects (2-20)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxPower.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+#ifndef __CMDTXPOWER_H__
+#define __CMDTXPOWER_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxPower: public Command
+{
+
+public:
+
+    CmdTxPower(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXPOWER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxWait.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,52 @@
+#include "CmdTxWait.h"
+
+CmdTxWait::CmdTxWait(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Tx wait", "AT+TXW", "Enable/disable waiting for rx windows to expire after send. (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdTxWait::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx wait: ");
+
+        _serial.writef("%u\r\n", _dot->getTxWait());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+
+        if ((code = _dot->setTxWait(args[1] == "1")) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxWait::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "0" && args[1] != "1") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxWait.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,21 @@
+
+#ifndef __CMDTXWAIT_H__
+#define __CMDTXWAIT_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdTxWait : public Command {
+
+public:
+
+    CmdTxWait(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXWAIT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Command.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,128 @@
+#include "Command.h"
+#include <algorithm>
+
+const char Command::newline[] = "\r\n";
+
+Command::Command(mDot* dot) : _dot(dot)
+{
+    _usage = "NONE";
+    _queryable = false;
+}
+
+Command::Command(mDot* dot, const char* name, const char* text, const char* desc) :
+    _dot(dot), _name(name), _text(text), _desc(desc)
+{
+    _usage = "NONE";
+    _queryable = false;
+}
+
+std::string &Command::errorMessage()
+{
+    return _errorMessage;
+}
+
+void Command::setErrorMessage(const char* message)
+{
+    _errorMessage.assign(message);
+}
+
+void Command::setErrorMessage(const std::string& message)
+{
+    _errorMessage.assign(message);
+}
+
+const std::string Command::usage() const
+{
+    std::string usage(_text);
+    usage.append(": ");
+    usage.append(_usage);
+    return usage;
+}
+
+const bool Command::queryable()
+{
+    return _queryable;
+}
+
+void Command::readByteArray(const std::string& input, std::vector<uint8_t>& out, size_t len)
+{
+    // if input length is greater than expected byte output
+    // there must be a delimiter included
+    if (input.length() > len * 2)
+    {
+        std::vector < std::string > bytes;
+        if (input.find(" ") != std::string::npos)
+            bytes = mts::Text::split(input, " ");
+        else if (input.find(":") != std::string::npos)
+            bytes = mts::Text::split(input, ":");
+        else if (input.find("-") != std::string::npos)
+            bytes = mts::Text::split(input, "-");
+        else if (input.find(".") != std::string::npos)
+            bytes = mts::Text::split(input, ".");
+
+        if (bytes.size() != len) {
+            return;
+        }
+
+        uint8_t temp;
+        // Read in the key components...
+        for (size_t i = 0; i < len; i++)
+        {
+            sscanf(bytes[i].c_str(), "%02x", &temp);
+            out.push_back(temp);
+        }
+    }
+    else
+    {
+        // no delims
+        uint8_t temp;
+
+        // Read in the key components...
+        for (size_t i = 0; i < len; i++)
+        {
+            if (i * 2 < input.size())
+            {
+                sscanf(input.substr(i * 2).c_str(), "%02x", &temp);
+                out.push_back(temp);
+            }
+        }
+    }
+}
+
+bool Command::isHexString(const std::string& str, size_t bytes) {
+    size_t numDelims = bytes - 1;
+    size_t minSize = bytes * 2;
+    size_t maxSize = minSize + numDelims;
+
+    if (str.size() == minSize) {
+        return str.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos;
+    }
+    else if (str.size() == maxSize) {
+        if (str.find_first_of(":-.") == std::string::npos) {
+            // no delim found
+            return false;
+        }
+        if (str.find(":") != std::string::npos && std::count(str.begin(), str.end(), ':') != numDelims) {
+            return false;
+        }
+        if (str.find(".") != std::string::npos && std::count(str.begin(), str.end(), '.') != numDelims) {
+            return false;
+        }
+        if (str.find("-") != std::string::npos && std::count(str.begin(), str.end(), '-') != numDelims) {
+            return false;
+        }
+
+        return str.find_first_not_of("0123456789abcdefABCDEF:-.") == std::string::npos;
+    }   
+
+    return false;
+}
+
+bool Command::verify(std::vector<std::string> args) {
+    if (args.size() == 1)
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Command.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,98 @@
+/**
+ ******************************************************************************
+ * File Name          : Command.h
+ * Date               : 18/04/2014 10:57:12
+ * Description        : This file provides code for command line prompt
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2014 MultiTech Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *   1. Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright notice,
+ *      this list of conditions and the following disclaimer in the documentation
+ *      and/or other materials provided with the distribution.
+ *   3. Neither the name of STMicroelectronics nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include "mbed.h"
+#include "mDot.h"
+#include "MTSSerial.h"
+#include "MTSText.h"
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include "limits.h"
+#include "debug.h"
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __command_H
+#define __command_H
+
+#define KEY_LENGTH 16
+#define EUI_LENGTH 8
+#define PASSPHRASE_LENGTH 128
+
+class Command {
+
+    public:
+
+        Command(mDot* dot);
+        Command(mDot* dot, const char* name, const char* text, const char* desc);
+        virtual ~Command() {};
+
+        const char* name() const { return _name; };
+        const char* text() const { return _text; };
+        const char* desc() const { return _desc; };
+        const char* help() const { return _help.c_str(); };
+
+        virtual uint32_t action(std::vector<std::string> args) = 0;
+        virtual bool verify(std::vector<std::string> args);
+        const std::string usage() const;
+        std::string& errorMessage();
+        const bool queryable();
+
+        static const char newline[];
+        static void readByteArray(const std::string& input, std::vector<uint8_t>& out, size_t len);
+
+        static bool isHexString(const std::string& str, size_t bytes);
+        static bool isBaudRate(uint32_t baud);
+
+    protected:
+
+        void setErrorMessage(const char* message);
+        void setErrorMessage(const std::string& message);
+        std::string _help;
+        std::string _usage;
+        bool _queryable;
+        mDot* _dot;
+
+    private:
+
+        const char* _name;
+        const char* _text;
+        const char* _desc;
+        std::string _errorMessage;
+
+};
+
+#endif /*__ command_H */
+
+/************************ (C) COPYRIGHT MultiTech Systems, Inc *****END OF FILE****/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CommandTerminal.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,684 @@
+#include "ctype.h"
+#include "CommandTerminal.h"
+#include "Command.h"
+#include <cstdarg>
+
+extern "C" {
+#include "wakeup.h"
+    extern void pin_function(PinName pin, int data);
+}
+
+const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa XBee Module\r\n\n";
+const char CommandTerminal::helpline[] = "Enter '?' for help\r\n";
+
+const char CommandTerminal::newline[] = "\r\n";
+
+// Command error text...
+const char CommandTerminal::command_error[] = "Command not found!\r\n";
+
+// Response texts...
+const char CommandTerminal::help[] = "\r\nHelp\r\n";
+const char CommandTerminal::cmd_error[] = "Invalid command\r\n";
+const char CommandTerminal::done[] = "\r\nOK\r\n";
+const char CommandTerminal::error[] = "\r\nERROR\r\n";
+
+// Escape sequence...
+const char CommandTerminal::escape_sequence[] = "+++";
+
+mts::MTSSerial* CommandTerminal::_serialp = NULL;
+
+void CommandTerminal::addCommand(Command* cmd) {
+    _commands.push_back(cmd);
+}
+
+CommandTerminal::CommandTerminal(mts::MTSSerial& serial, mDot* dot)
+:
+  _serial(serial),
+  _dot(dot),
+  _mode(mDot::COMMAND_MODE),
+  _sleep_standby(false),
+  _xbee_on_sleep(XBEE_ON_SLEEP),
+  _serial_up(false) {
+
+    _serialp = &serial;
+
+    wakeup_init(_dot->getSerialWakeInterval());
+
+    addCommand(new CmdAttention(_dot));
+    addCommand(new CmdIdentification(_dot, serial));
+    addCommand(new CmdResetCpu(_dot, serial));
+    addCommand(new CmdDummy(_dot, "Enable/Disable Echo", "ATE0/1", "ATE0: disable, ATE1: enable"));
+    addCommand(new CmdDummy(_dot, "Enable/Disable Verbose", "ATV0/1", "ATV0: disable, ATV1: enable"));
+
+    addCommand(new CmdFactoryDefault(_dot));
+    addCommand(new CmdSaveConfig(_dot));
+    addCommand(new CmdDisplayConfig(_dot, serial));
+    addCommand(new CmdDisplayStats(_dot, serial));
+    addCommand(new CmdSerialBaudRate(_dot, serial));
+    addCommand(new CmdDebugBaudRate(_dot, serial));
+    addCommand(new CmdStartUpMode(_dot, serial));
+
+    addCommand(new CmdFrequencyBand(_dot, serial));
+    addCommand(new CmdFrequencySubBand(_dot, serial));
+    addCommand(new CmdPublicNetwork(_dot, serial));
+    addCommand(new CmdDeviceId(_dot, serial));
+
+    addCommand(new CmdNetworkAddress(_dot, serial));
+    addCommand(new CmdNetworkSessionKey(_dot, serial));
+    addCommand(new CmdDataSessionKey(_dot, serial));
+    addCommand(new CmdNetworkKey(_dot, serial));
+    addCommand(new CmdNetworkId(_dot, serial));
+
+    addCommand(new CmdJoinRequest(_dot, serial));
+    addCommand(new CmdJoinRetries(_dot, serial));
+    addCommand(new CmdNetworkJoinMode(_dot, serial));
+    addCommand(new CmdNetworkJoinStatus(_dot, serial));
+    addCommand(new CmdNetworkLinkCheck(_dot, serial));
+    addCommand(new CmdLinkCheckCount(_dot, serial));
+    addCommand(new CmdLinkCheckThreshold(_dot, serial));
+    addCommand(new CmdEncryption(_dot, serial));
+
+    addCommand(new CmdRssi(_dot, serial));
+    addCommand(new CmdSnr(_dot, serial));
+    addCommand(new CmdDataPending(_dot, serial));
+
+    addCommand(new CmdTxDataRate(_dot, serial));
+    addCommand(new CmdTxPower(_dot, serial));
+    addCommand(new CmdTxFrequency(_dot, serial));
+    addCommand(new CmdTxInverted(_dot, serial));
+    addCommand(new CmdTxWait(_dot, serial));
+    addCommand(new CmdTxChannel(_dot, serial));
+    addCommand(new CmdTxNextMs(_dot, serial));
+    addCommand(new CmdTimeOnAir(_dot, serial));
+
+    addCommand(new CmdRxDataRate(_dot, serial));
+    addCommand(new CmdRxFrequency(_dot, serial));
+    addCommand(new CmdRxOutput(_dot, serial));
+    addCommand(new CmdRxInverted(_dot, serial));
+
+    addCommand(new CmdErrorCorrection(_dot, serial));
+    addCommand(new CmdCRC(_dot, serial));
+    addCommand(new CmdAdaptiveDataRate(_dot, serial));
+
+    addCommand(new CmdACKAttempts(_dot, serial));
+
+    addCommand(new CmdSendString(_dot, serial));
+    addCommand(new CmdSendStringHighBW(_dot, serial));
+    addCommand(new CmdSendBinary(_dot, serial));
+    addCommand(new CmdSendStringOnInterval(_dot, serial));
+    addCommand(new CmdReceiveOnce(_dot, serial));
+    addCommand(new CmdReceiveContinuous(_dot, serial));
+
+    addCommand(new CmdDummy(_dot, "Serial Data Mode", "AT+SD", "Reads serial data and sends Lora packets (escape sequence: +++)"));
+    addCommand(new CmdSerialWakeInterval(_dot, serial));
+    addCommand(new CmdSerialWakeDelay(_dot, serial));
+    addCommand(new CmdSerialReceiveTimeout(_dot, serial));
+    addCommand(new CmdPing(_dot, serial));
+    addCommand(new CmdLogLevel(_dot, serial));
+}
+
+void CommandTerminal::printHelp() {
+    const char* name = NULL;
+    const char* text = NULL;
+    const char* desc = NULL;
+    const char* tab = "\t";
+
+    std::string header("Command");
+    header.append(tab);
+    header.append(tab);
+    header.append("Name");
+    header.append(tab);
+    header.append(tab);
+    header.append(tab);
+    header.append("Description");
+
+    write(newline);
+    write(header.c_str());
+    write(newline);
+    write(newline);
+    for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
+        name = (*it)->name();
+        text = (*it)->text();
+        desc = (*it)->desc();
+        write(text);
+        if (strlen(text) < 8)
+            write(tab);
+        write(tab);
+        write(name);
+        if (strlen(name) < 8)
+            write(tab);
+        if (strlen(name) < 16)
+            write(tab);
+        write(tab);
+        write(desc);
+        write(newline);
+    }
+
+    write(newline);
+}
+
+bool CommandTerminal::writeable() {
+    return _serial.writeable();
+}
+
+bool CommandTerminal::readable() {
+    return _serial.readable();
+}
+
+char CommandTerminal::read() {
+    char ch;
+    _serial.read(&ch, 1);
+    return ch;
+}
+
+void CommandTerminal::write(const char* message) {
+    while (!writeable())
+        ;
+    _serial.write(message, strlen(message));
+}
+
+void CommandTerminal::writef(const char* format, ...) {
+    char buff[256];
+
+    va_list ap;
+    va_start(ap, format);
+    int size = vsnprintf(buff, 256, format, ap);
+    while (!writeable())
+        ;
+    _serial.write(buff, size);
+    va_end(ap);
+}
+
+void CommandTerminal::serial_loop() {
+    Timer serial_read_timer;
+    std::vector<uint8_t> serial_buffer;
+    std::string escape_buffer;
+    Timer escape_timer;
+    int escape_delay = 100;
+    uint8_t max_send_size;
+
+    _serial_up = true;
+    _xbee_on_sleep = GPIO_PIN_SET;
+
+    if (_dot->getFrequencyBand() == mDot::FB_915)
+        max_send_size = mDot::MaxLengths_915[_dot->getTxDataRate()];
+    else
+        max_send_size = mDot::MaxLengths_868[_dot->getTxDataRate()];
+
+    DEBUG_PRINTF("Awake\r\n");
+    wakeup(_sleep_standby);
+
+    char ch;
+
+    if (readable()) {
+        ch = read();
+        serial_buffer.push_back(ch);
+
+        if (escape_timer.read_ms() > escape_delay && ch == '+') {
+            escape_buffer += ch;
+            escape_timer.reset();
+        } else {
+            _serial_up = true;
+            escape_buffer.clear();
+        }
+
+        if (escape_buffer.length() == 3 && escape_buffer.find(escape_sequence) == 0) {
+            _mode = mDot::COMMAND_MODE;
+            DEBUG_PRINTF("Exit serial mode\r\n");
+            escape_timer.stop();
+            escape_buffer.clear();
+            write(done);
+            return;
+        }
+    }
+
+    if (_serial_up) {
+        osDelay(_dot->getSerialWakeDelay());
+
+        serial_read_timer.start();
+        while (_serial_up && serial_read_timer.read_ms() < _dot->getSerialReceiveTimeout()) {
+            while (readable() && serial_buffer.size() < max_send_size) {
+                serial_buffer.push_back(read());
+                serial_read_timer.reset();
+            }
+        }
+        serial_read_timer.stop(), serial_read_timer.reset();
+
+        if (!serial_buffer.empty()) {
+            _serial_up = false;
+            _xbee_on_sleep = GPIO_PIN_RESET;
+            if (!_dot->getIsTransmitting()) {
+                std::vector<uint8_t> recv_buffer;
+                DEBUG_PRINTF("Received serial data, sending out radio.\r\n");
+
+                if (!_dot->send(serial_buffer))
+                    DEBUG_PRINTF("Send failed.\r\n");
+                if (_dot->recv(recv_buffer))
+                    _serial.writef("%s\r\n", formatPacketData(recv_buffer, _dot->getRxOutput()).c_str());
+            } else {
+                DEBUG_PRINTF("Radio is busy, cannot send.\r\n");
+            }
+
+            serial_buffer.clear();
+        } else {
+            DEBUG_PRINTF("No data received from serial to send.\r\n");
+        }
+        _serial_up = false;
+    }
+    sleep(_sleep_standby);
+}
+
+bool CommandTerminal::autoJoinCheck() {
+
+    std::string escape_buffer;
+    char ch;
+    int sleep = 1000;
+    int escape_timeout = 1000;
+    Timer tmr;
+    Timer escape_tmr;
+    int cnt = 0;
+
+    while (!_dot->getNetworkJoinStatus()) {
+        wakeup(_sleep_standby);
+        write("\r\nJoining network... ");
+
+        // wait one second for possible escape
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < 1000) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                write("Join Canceled\r\n");
+                write(done);
+                return true;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+        }
+
+        if (_dot->joinNetworkOnce() == mDot::MDOT_OK) {
+            write("Network Joined\r\n");
+            write(done);
+            return false;
+        }
+
+        write("Network Join failed\r\n");
+        write(error);
+
+        if (cnt++ > _dot->getJoinRetries()) {
+            cnt = 0;
+
+            if (_dot->getFrequencyBand() == mDot::FB_915) {
+                uint8_t band = ((_dot->getFrequencySubBand()) % 8) + 1;
+                DEBUG_PRINTF("Join retries exhausted, switching to sub band %u\r\n", band);
+                _dot->setFrequencySubBand(band);
+            }
+
+            if (sleep < 60 * 60 * 1000)
+                sleep *= 2;
+        }
+
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < sleep) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                return true;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+        }
+
+    }
+
+    return false;
+}
+
+void CommandTerminal::start() {
+
+    _dot->resetNetworkSession();
+
+    char ch;
+    bool running = true;
+    bool echo = _dot->getEcho();
+    std::string command;
+    std::vector<std::string> args;
+
+    if (_dot->getStartUpMode() == mDot::SERIAL_MODE) {
+        command = "AT+SD\n";
+
+        std::string escape_buffer;
+        char ch;
+
+        int escape_timeout = 1000;
+        Timer tmr;
+        Timer escape_tmr;
+
+        // wait one second for possible escape
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < escape_timeout) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                command.clear();
+                break;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+
+            osDelay(1);
+        }
+
+    }
+
+    bool join_canceled = false;
+
+    //Run terminal session
+    while (running) {
+        if (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA) {
+            join_canceled = autoJoinCheck();
+            if (join_canceled)
+                command.clear();
+        }
+
+        if (_dot->getJoinMode() != mDot::AUTO_OTA || (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA)) {
+            switch (_mode) {
+                case mDot::SERIAL_MODE:
+                    // signal wakeup, read serial and output to radio
+                    serial_loop();
+                    continue;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        ch = '\0';
+
+        // read characters
+        if (readable()) {
+            ch = read();
+
+            if (ch == '\b') {
+                if (!command.empty()) {
+                    writef("\b \b");
+                    command.erase(command.size() - 1);
+                }
+                continue;
+            } else {
+                command += ch;
+            }
+
+            // echo chars if enabled
+            if (echo && !(ch == '\r' || ch == '\n'))
+                writef("%c", ch);
+        }
+
+        // look for end of command line
+        if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
+            // remove new line or cr character
+            command.erase(command.size() - 1);
+            write("\r"); // match standard modem output
+            write(newline);
+        } else {
+            continue;
+        }
+
+        // trim whitespace from command
+        mts::Text::trim(command, "\r\n\t ");
+
+        if (command.size() < 1) {
+            command.clear();
+            continue;
+        }
+
+        // parse command and args
+        args.clear();
+
+        // find first '=' character
+        size_t delim_index = command.find("=");
+        if (delim_index != std::string::npos) {
+            args.push_back(command.substr(0, delim_index));
+        } else {
+            // find first ' ' character
+            delim_index = command.find(" ");
+            if (delim_index != std::string::npos) {
+                args.push_back(command.substr(0, delim_index));
+            } else {
+                args.push_back(command);
+            }
+        }
+
+        if (delim_index != std::string::npos) {
+            std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
+            args.insert(args.end(), params.begin(), params.end());
+        }
+
+        args[0] = mts::Text::toUpper(args[0]);
+
+        // print help
+        if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
+            printHelp();
+            command.clear();
+        } else if (args[0].find("ATE0") == 0 && args[0].length() == 4) {
+            _dot->setEcho(false);
+            write(done);
+            echo = _dot->getEcho();
+        } else if (args[0].find("ATE1") == 0 && args[0].length() == 4) {
+            _dot->setEcho(true);
+            write(done);
+            echo = _dot->getEcho();
+        } else if (args[0].find("ATV0") == 0 && args[0].length() == 4) {
+            _dot->setVerbose(false);
+            write(done);
+        } else if (args[0].find("ATV1") == 0 && args[0].length() == 4) {
+            _dot->setVerbose(true);
+            write(done);
+        } else if (args[0] == "AT+SD") {
+            DEBUG_PRINTF("Enter Serial Mode\r\n");
+            _mode = mDot::SERIAL_MODE;
+        } else {
+            bool found = false;
+            bool query = false;
+
+            std::string lookfor = args[0];
+
+            // per command help
+            if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
+                lookfor = mts::Text::toUpper(args[1]);
+
+            // trim off any trailing '?' and mark as a query command
+            if (args[0].rfind("?") == args[0].length() - 1) {
+                query = true;
+                lookfor = args[0].substr(0, args[0].length() - 1);
+            }
+
+            // search for command
+            for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
+                Command* cmd = *it;
+
+                // match CMD or CMD? syntax if command is queryable
+                if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
+                    found = true;
+                    if (args[0] == "HELP") {
+                        writef("%s%s", cmd->help(), newline);
+                        write(done);
+                    }
+
+                    else if (args.size() > 1 && args[1] == "?") {
+                        writef("%s%s", cmd->usage().c_str(), newline);
+                        write(done);
+                    } else if (!cmd->verify(args)) {
+                        writef("%s%s", cmd->errorMessage().c_str(), newline);
+                        writef("%s", error);
+                    } else {
+                        if (cmd->action(args) == 0) {
+                            writef("%s", done);
+                        } else {
+                            writef("%s%s", cmd->errorMessage().c_str(), newline);
+                            writef("%s", error);
+                        }
+                    }
+                }
+            }
+
+            if (!found) {
+                writef("%s", command_error);
+                writef("%s", error);
+            }
+        }
+
+        command.clear();
+
+    }
+}
+
+std::string CommandTerminal::formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format) {
+    if (format == mDot::HEXADECIMAL) {
+        return mts::Text::bin2hexString(data);
+    } else {
+        std::string data_str;
+        for (int i = 0; i < data.size(); i++)
+            data_str.append((const char*)data[i], 1);
+        return data_str;
+    }
+}
+
+void CommandTerminal::sleep(bool standby) {
+    _serial_up = false;
+    _xbee_on_sleep = GPIO_PIN_RESET;
+
+    HAL_PWREx_EnableMainRegulatorLowVoltage();
+    HAL_PWREx_EnableFlashPowerDown();
+    HAL_PWREx_EnableLowRegulatorLowVoltage();
+
+    DEBUG_PRINTF("Sleep\r\n");
+    _dot->sleep();
+
+    if (standby) {
+
+        DEBUG_PRINTF("RECORD UPLINK: %lu\r\n", _dot->getUpLinkCounter());
+
+        RTC_WriteBackupRegister(RTC_BKP_DR0, _dot->getUpLinkCounter());
+
+        HAL_PWR_EnableBkUpAccess();
+
+        HAL_EnableDBGStandbyMode();
+
+        HAL_PWR_DisableWakeUpPin (PWR_WAKEUP_PIN1);
+
+        __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // InterruptIn wakeon_serial(XBEE_DIN);
+        // Application is reloaded after wake-up from standby
+HAL_PWR_EnterSTANDBYMode        ();
+
+    } else {
+        pin_function(PA_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_3, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_6, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_7, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_8, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_10, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_11, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_12, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_15, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PB_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PB_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PB_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PC_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PC_13, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PD_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
+    }
+
+    wakeup_clear();
+    EXTI->PR = (1 << 22);
+
+    // After wake-up from STOP reconfigure the PLL
+    SetSysClock();
+}
+
+bool CommandTerminal::waitForEscape(int timeout, mDot* dot, WaitType wait) {
+    Timer timer;
+    Timer escape_timer;
+    std::string escape_buffer;
+    int escape_timeout = 1000;
+
+    timer.start();
+    while (timer.read_ms() < timeout) {
+
+        if (dot != NULL) {
+            if (wait == WAIT_SEND && (!dot->getIsTransmitting())) {
+                return false;
+            }
+        }
+
+        if (_serialp != NULL && _serialp->readable()) {
+            if (escape_buffer == "")
+                escape_timer.start();
+            char ch;
+            _serialp->read(&ch, 1);
+            escape_buffer += ch;
+            if (escape_buffer == CommandTerminal::escape_sequence)
+                return true;
+        }
+        if (escape_timer.read_ms() > escape_timeout) {
+            escape_buffer = "";
+            escape_timer.stop(), escape_timer.reset();
+        }
+
+        osDelay(10);
+    }
+
+    return false;
+}
+
+void CommandTerminal::wakeup(bool standby) {
+    HAL_PWREx_DisableMainRegulatorLowVoltage();
+    HAL_PWREx_DisableFlashPowerDown();
+    HAL_PWREx_DisableLowRegulatorLowVoltage();
+
+    if (standby) {
+        HAL_DisableDBGStandbyMode();
+
+        HAL_PWR_EnableWakeUpPin (PWR_WAKEUP_PIN1);
+    }
+
+    _dot->wakeup();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CommandTerminal.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,112 @@
+/**
+  ******************************************************************************
+  * File Name          : command.h
+  * Date               : 18/04/2014 10:57:12
+  * Description        : This file provides code for command line prompt
+  ******************************************************************************
+  *
+  * COPYRIGHT(c) 2014 MultiTech Systems, Inc.
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+  
+#include "mbed.h"
+#include "MTSSerial.h"
+#include "Commands.h"
+#include "mDot.h"
+  
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __command_terminal_H__
+#define __command_terminal_H__
+
+class CommandTerminal {
+
+public:
+
+    enum WaitType {
+        WAIT_JOIN,
+        WAIT_RECV,
+        WAIT_LINK,
+        WAIT_SEND,
+        WAIT_NA
+    };
+
+    CommandTerminal(mts::MTSSerial& serial, mDot* dot);
+    
+    // Command prompt text...
+    static const char banner[];
+    static const char helpline[];
+    static const char prompt[];
+    
+    // Command error text...
+    static const char command_error[];
+    
+    // Response texts...
+    static const char help[];
+    static const char cmd_error[];
+    static const char newline[];
+    static const char done[];
+    static const char error[];
+
+    // Escape sequence
+    static const char escape_sequence[];
+    
+    static std::string formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format);
+    static bool waitForEscape(int timeout, mDot* dot=NULL, WaitType wait=WAIT_NA);
+
+    void start();
+    
+private: 
+
+    mts::MTSSerial& _serial;
+    static mts::MTSSerial* _serialp;
+
+    mDot* _dot;
+    mDot::Mode _mode;
+    std::vector<Command*> _commands;
+    bool _sleep_standby;
+    DigitalOut _xbee_on_sleep;
+    bool _serial_up;
+
+    void addCommand(Command* cmd);
+    
+    void serial_loop();
+    bool autoJoinCheck();
+
+    void printHelp();
+
+    bool readable();
+    bool writeable();
+    char read();
+    void write(const char* message);
+    void writef(const char* format, ... );
+
+    void sleep(bool standby);
+    void wakeup(bool standby);
+    
+};
+
+#endif // __command_terminal_H__
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Commands.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,75 @@
+#include "Command.h"
+#include "CmdDummy.h"
+
+#include "CmdAttention.h"
+#include "CmdIdentification.h"
+#include "CmdResetCpu.h"
+// Echo built into command terminal
+// Verbose built into command terminal
+//
+#include "CmdFactoryDefault.h"
+#include "CmdSaveConfig.h"
+#include "CmdDisplayConfig.h"
+#include "CmdDisplayStats.h"
+
+#include "CmdSerialBaudRate.h"
+#include "CmdDebugBaudRate.h"
+#include "CmdStartUpMode.h"
+
+#include "CmdFrequencyBand.h"
+#include "CmdDeviceId.h"
+#include "CmdPublicNetwork.h"
+#include "CmdNetworkAddress.h"
+#include "CmdNetworkSessionKey.h"
+#include "CmdDataSessionKey.h"
+#include "CmdNetworkKey.h"
+#include "CmdNetworkId.h"
+#include "CmdJoinRequest.h"
+#include "CmdJoinRetries.h"
+#include "CmdNetworkJoinMode.h"
+#include "CmdNetworkJoinStatus.h"
+#include "CmdNetworkLinkCheck.h"
+#include "CmdLinkCheckCount.h"
+#include "CmdLinkCheckThreshold.h"
+#include "CmdEncryption.h"
+#include "CmdRssi.h"
+#include "CmdSnr.h"
+#include "CmdDataPending.h"
+
+#include "CmdTxDataRate.h"
+#include "CmdTxPower.h"
+#include "CmdTxWait.h"
+#include "CmdTxInverted.h"
+#include "CmdTxChannel.h"
+#include "CmdTxNextMs.h"
+#include "CmdTimeOnAir.h"
+#include "CmdFrequencySubBand.h"
+
+#include "CmdRxDataRate.h"
+#include "CmdRxFrequency.h"
+#include "CmdRxOutput.h"
+#include "CmdRxInverted.h"
+
+#include "CmdErrorCorrection.h"
+#include "CmdCRC.h"
+#include "CmdAdaptiveDataRate.h"
+
+#include "CmdACKAttempts.h"
+#include "CmdSendString.h"
+#include "CmdSendStringHighBW.h"
+#include "CmdSendBinary.h"
+#include "CmdSendStringOnInterval.h"
+#include "CmdReceiveOnce.h"
+#include "CmdReceiveContinuous.h"
+
+// Serial Data Mode built into command terminal
+#include "CmdSerialWakeInterval.h"
+#include "CmdSerialWakeDelay.h"
+#include "CmdSerialReceiveTimeout.h"
+#include "CmdPing.h"
+
+#include "CmdLogLevel.h"
+
+// Radio debug commands
+
+#include "CmdTxFrequency.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Test/TestCommandTerminal.h	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,82 @@
+#ifndef TESTCOMMANDTERMINAL_H
+#define TESTCOMMANDTERMINAL_H
+
+#include <string>
+#include <vector>
+
+#include "Commands.h"
+
+class MockSerial
+{
+
+public:
+    std::string read_buff;
+    std::string write_buff;
+
+    int read(char* buff, int len)
+    {
+
+        return 0;
+    }
+
+    int write(char* buff)
+    {
+        write_buff.append(buff);
+        return 0;
+    }
+
+    int writef(char* buff)
+    {
+        printf("MockSerial writef\r\n");
+        write_buff.append(buff);
+        return 0;
+    }
+};
+
+class TestCommandTerminal: public TestCollection
+{
+public:
+    TestCommandTerminal();
+    ~TestCommandTerminal();
+
+    virtual void run();
+
+};
+
+TestCommandTerminal::TestCommandTerminal() :
+        TestCollection("CommandTerminal")
+{
+}
+
+TestCommandTerminal::~TestCommandTerminal()
+{
+}
+
+void TestCommandTerminal::run()
+{
+    MockSerial test_serial;
+
+    Test::start("Test AT");
+    CmdAttention at_cmd;
+    Test::assertTrue(std::string("AT").compare(at_cmd.text()) == 0);
+    std::vector < std::string > args;
+    args.push_back("AT");
+    args.push_back("IGNORED");
+    Test::assertTrue(at_cmd.verify(args));
+    Test::assertTrue(at_cmd.action(args) == 0);
+    Test::end();
+
+//    Test::start("Test ATI");
+//    printf("testing ati\r\n");
+//    CmdIdentification ati_cmd((mts::MTSSerial&)test_serial);
+//    printf("cmd created\r\n");
+//    Test::assertTrue(at_cmd.verify(args));
+//    printf("verified\r\n");
+//    Test::assertTrue(at_cmd.action(args) == 0);
+//    printf("actionied\r\n");
+//    Test::assertTrue(test_serial.write_buff.find("MultiTech") == 0);
+//    Test::end();
+
+}
+
+#endif /* TESTCOMMANDTERMINAL_H */
--- a/debug.h	Thu Jun 25 14:52:56 2015 +0000
+++ b/debug.h	Thu Jun 25 10:23:41 2015 -0500
@@ -1,12 +1,8 @@
 #include "mbed.h"
 #include <stdio.h>
 
-// enable to turn on debug prints
-#define DEBUG_MAC 1
-
-#ifdef DEBUG_MAC
-    #define MTS_RADIO_DEBUG_COMMANDS 1
+#if 1
     #define DEBUG_PRINTF(fmt, args...)  printf("%s:%d: "fmt, __FUNCTION__, __LINE__, ## args)
 #else
     #define DEBUG_PRINTF(fmt, args...)
-#endif
\ No newline at end of file
+#endif
--- a/main.cpp	Thu Jun 25 14:52:56 2015 +0000
+++ b/main.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -26,4 +26,4 @@
     CommandTerminal term(serial, dot);
 
     term.start();
-}
\ No newline at end of file
+}
--- a/version.h	Thu Jun 25 14:52:56 2015 +0000
+++ b/version.h	Thu Jun 25 10:23:41 2015 -0500
@@ -3,4 +3,4 @@
 
 #define AT_APPLICATION_VERSION "060215_mbed-19-gdadc7ac"
 
-#endif
\ No newline at end of file
+#endif
--- a/wakeup.c	Thu Jun 25 14:52:56 2015 +0000
+++ b/wakeup.c	Thu Jun 25 10:23:41 2015 -0500
@@ -150,4 +150,4 @@
 void TM_WATCHDOG_Reset(void) {
     /* Reload IWDG counter */
     IWDG->KR = 0xAAAA;
-}
\ No newline at end of file
+}
--- a/wakeup.h	Thu Jun 25 14:52:56 2015 +0000
+++ b/wakeup.h	Thu Jun 25 10:23:41 2015 -0500
@@ -111,4 +111,4 @@
 
 #endif
 
-#endif // __WAKEUP_H__
\ No newline at end of file
+#endif // __WAKEUP_H__