summaryrefslogtreecommitdiff
path: root/CommandTerminal
diff options
context:
space:
mode:
Diffstat (limited to 'CommandTerminal')
-rw-r--r--CommandTerminal/CmdAttention.cpp16
-rw-r--r--CommandTerminal/CmdAttention.h17
-rw-r--r--CommandTerminal/CmdDataSessionKey.cpp56
-rw-r--r--CommandTerminal/CmdDataSessionKey.h20
-rw-r--r--CommandTerminal/CmdDeviceId.cpp57
-rw-r--r--CommandTerminal/CmdDeviceId.h21
-rw-r--r--CommandTerminal/CmdDisplayConfig.cpp106
-rw-r--r--CommandTerminal/CmdDisplayConfig.h19
-rw-r--r--CommandTerminal/CmdFactoryDefault.cpp15
-rw-r--r--CommandTerminal/CmdFactoryDefault.h16
-rw-r--r--CommandTerminal/CmdFrequencySubBand.cpp60
-rw-r--r--CommandTerminal/CmdFrequencySubBand.h20
-rw-r--r--CommandTerminal/CmdIdentification.cpp20
-rw-r--r--CommandTerminal/CmdIdentification.h17
-rw-r--r--CommandTerminal/CmdNetworkAddress.cpp72
-rw-r--r--CommandTerminal/CmdNetworkAddress.h20
-rw-r--r--CommandTerminal/CmdNetworkId.cpp110
-rw-r--r--CommandTerminal/CmdNetworkId.h20
-rw-r--r--CommandTerminal/CmdNetworkJoinMode.cpp55
-rw-r--r--CommandTerminal/CmdNetworkJoinMode.h20
-rw-r--r--CommandTerminal/CmdNetworkKey.cpp110
-rw-r--r--CommandTerminal/CmdNetworkKey.h22
-rw-r--r--CommandTerminal/CmdNetworkSessionKey.cpp57
-rw-r--r--CommandTerminal/CmdNetworkSessionKey.h20
-rw-r--r--CommandTerminal/CmdPublicNetwork.cpp52
-rw-r--r--CommandTerminal/CmdPublicNetwork.h21
-rw-r--r--CommandTerminal/CmdSaveConfig.cpp17
-rw-r--r--CommandTerminal/CmdSaveConfig.h17
-rw-r--r--CommandTerminal/CmdTxDataRate.cpp89
-rw-r--r--CommandTerminal/CmdTxDataRate.h20
-rw-r--r--CommandTerminal/CmdTxPower.cpp62
-rw-r--r--CommandTerminal/CmdTxPower.h21
-rw-r--r--CommandTerminal/Command.cpp128
-rw-r--r--CommandTerminal/Command.h98
-rw-r--r--CommandTerminal/CommandTerminal.cpp631
-rw-r--r--CommandTerminal/CommandTerminal.h118
-rw-r--r--CommandTerminal/Commands.h19
-rw-r--r--CommandTerminal/Test/TestCommandTerminal.h82
38 files changed, 2341 insertions, 0 deletions
diff --git a/CommandTerminal/CmdAttention.cpp b/CommandTerminal/CmdAttention.cpp
new file mode 100644
index 0000000..892e891
--- /dev/null
+++ b/CommandTerminal/CmdAttention.cpp
@@ -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;
+}
+
diff --git a/CommandTerminal/CmdAttention.h b/CommandTerminal/CmdAttention.h
new file mode 100644
index 0000000..76fd1d2
--- /dev/null
+++ b/CommandTerminal/CmdAttention.h
@@ -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__
diff --git a/CommandTerminal/CmdDataSessionKey.cpp b/CommandTerminal/CmdDataSessionKey.cpp
new file mode 100644
index 0000000..d663406
--- /dev/null
+++ b/CommandTerminal/CmdDataSessionKey.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdDataSessionKey.h b/CommandTerminal/CmdDataSessionKey.h
new file mode 100644
index 0000000..704af6e
--- /dev/null
+++ b/CommandTerminal/CmdDataSessionKey.h
@@ -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__
diff --git a/CommandTerminal/CmdDeviceId.cpp b/CommandTerminal/CmdDeviceId.cpp
new file mode 100644
index 0000000..05d2301
--- /dev/null
+++ b/CommandTerminal/CmdDeviceId.cpp
@@ -0,0 +1,57 @@
+#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());
+ }
+#ifdef DEBUG_MAC
+ else if (args.size() == 2)
+ {
+ int32_t code;
+ std::vector<uint8_t> NewEUI;
+
+ // Read in the key components...
+ readByteArray(args[1], NewEUI, EUI_LENGTH);
+
+ if ((code = _dot->setDeviceId(NewEUI)) == mDot::MDOT_OK) {
+ _serial.writef("Set %s: ", name());
+ _serial.writef("%s\r\n", mts::Text::bin2hexString(NewEUI, ":").c_str());
+ } else {
+ std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+ setErrorMessage(error);
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+bool CmdDeviceId::verify(std::vector<std::string> args)
+{
+ if (args.size() == 1)
+ return true;
+
+#ifdef DEBUG_MAC
+ if (args.size() == 2 && isHexString(args[1], 8))
+ return true;
+
+ setErrorMessage("Invalid id, expects (hex:8)");
+#else
+ setErrorMessage("Invalid arguments");
+#endif
+
+ return false;
+}
diff --git a/CommandTerminal/CmdDeviceId.h b/CommandTerminal/CmdDeviceId.h
new file mode 100644
index 0000000..9e1ad74
--- /dev/null
+++ b/CommandTerminal/CmdDeviceId.h
@@ -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__
diff --git a/CommandTerminal/CmdDisplayConfig.cpp b/CommandTerminal/CmdDisplayConfig.cpp
new file mode 100644
index 0000000..6ef6e92
--- /dev/null
+++ b/CommandTerminal/CmdDisplayConfig.cpp
@@ -0,0 +1,106 @@
+#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("Join Byte Order:\t%s\r\n", _dot->getJoinByteOrder() ? "MSB" : "LSB");
+
+ _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("Wake Mode:\t\t%s\r\n", _dot->getWakeMode() == 0 ? "INTERVAL" : "INTERRUPT");
+ _serial.writef("Wake Interval:\t\t%lu s\r\n", _dot->getWakeInterval());
+ _serial.writef("Wake Delay:\t\t%lu ms\r\n", _dot->getWakeDelay());
+ _serial.writef("Wake Timeout:\t\t%u ms\r\n", _dot->getWakeTimeout());
+
+ //_serial.writef("Wake Pin:\t\t%s\r\n", mDot::pinName2Str(_dot->getWakePin()).c_str());
+
+ _serial.writef("Log Level:\t\t%ld\r\n", _dot->getLogLevel());
+
+ return 0;
+}
+
diff --git a/CommandTerminal/CmdDisplayConfig.h b/CommandTerminal/CmdDisplayConfig.h
new file mode 100644
index 0000000..05e7ac9
--- /dev/null
+++ b/CommandTerminal/CmdDisplayConfig.h
@@ -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__
diff --git a/CommandTerminal/CmdFactoryDefault.cpp b/CommandTerminal/CmdFactoryDefault.cpp
new file mode 100644
index 0000000..53b6ede
--- /dev/null
+++ b/CommandTerminal/CmdFactoryDefault.cpp
@@ -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;
+}
+
diff --git a/CommandTerminal/CmdFactoryDefault.h b/CommandTerminal/CmdFactoryDefault.h
new file mode 100644
index 0000000..8957ae3
--- /dev/null
+++ b/CommandTerminal/CmdFactoryDefault.h
@@ -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__
diff --git a/CommandTerminal/CmdFrequencySubBand.cpp b/CommandTerminal/CmdFrequencySubBand.cpp
new file mode 100644
index 0000000..fb9f0ba
--- /dev/null
+++ b/CommandTerminal/CmdFrequencySubBand.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdFrequencySubBand.h b/CommandTerminal/CmdFrequencySubBand.h
new file mode 100644
index 0000000..14d50c9
--- /dev/null
+++ b/CommandTerminal/CmdFrequencySubBand.h
@@ -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__
diff --git a/CommandTerminal/CmdIdentification.cpp b/CommandTerminal/CmdIdentification.cpp
new file mode 100644
index 0000000..a765b30
--- /dev/null
+++ b/CommandTerminal/CmdIdentification.cpp
@@ -0,0 +1,20 @@
+#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 = MTDOT_BOX_VERSION;
+#ifdef DEBUG_MAC
+ version += "-debug";
+#endif
+ _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;
+}
diff --git a/CommandTerminal/CmdIdentification.h b/CommandTerminal/CmdIdentification.h
new file mode 100644
index 0000000..b553ba1
--- /dev/null
+++ b/CommandTerminal/CmdIdentification.h
@@ -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__
diff --git a/CommandTerminal/CmdNetworkAddress.cpp b/CommandTerminal/CmdNetworkAddress.cpp
new file mode 100644
index 0000000..07c0591
--- /dev/null
+++ b/CommandTerminal/CmdNetworkAddress.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdNetworkAddress.h b/CommandTerminal/CmdNetworkAddress.h
new file mode 100644
index 0000000..7be2dd0
--- /dev/null
+++ b/CommandTerminal/CmdNetworkAddress.h
@@ -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__
diff --git a/CommandTerminal/CmdNetworkId.cpp b/CommandTerminal/CmdNetworkId.cpp
new file mode 100644
index 0000000..fffe9f7
--- /dev/null
+++ b/CommandTerminal/CmdNetworkId.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdNetworkId.h b/CommandTerminal/CmdNetworkId.h
new file mode 100644
index 0000000..09acdc6
--- /dev/null
+++ b/CommandTerminal/CmdNetworkId.h
@@ -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__
diff --git a/CommandTerminal/CmdNetworkJoinMode.cpp b/CommandTerminal/CmdNetworkJoinMode.cpp
new file mode 100644
index 0000000..b5efdf6
--- /dev/null
+++ b/CommandTerminal/CmdNetworkJoinMode.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdNetworkJoinMode.h b/CommandTerminal/CmdNetworkJoinMode.h
new file mode 100644
index 0000000..81d00d0
--- /dev/null
+++ b/CommandTerminal/CmdNetworkJoinMode.h
@@ -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__
diff --git a/CommandTerminal/CmdNetworkKey.cpp b/CommandTerminal/CmdNetworkKey.cpp
new file mode 100644
index 0000000..f85725c
--- /dev/null
+++ b/CommandTerminal/CmdNetworkKey.cpp
@@ -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;
+}
+
diff --git a/CommandTerminal/CmdNetworkKey.h b/CommandTerminal/CmdNetworkKey.h
new file mode 100644
index 0000000..f2874cc
--- /dev/null
+++ b/CommandTerminal/CmdNetworkKey.h
@@ -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__
diff --git a/CommandTerminal/CmdNetworkSessionKey.cpp b/CommandTerminal/CmdNetworkSessionKey.cpp
new file mode 100644
index 0000000..4d42505
--- /dev/null
+++ b/CommandTerminal/CmdNetworkSessionKey.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdNetworkSessionKey.h b/CommandTerminal/CmdNetworkSessionKey.h
new file mode 100644
index 0000000..4d8cc46
--- /dev/null
+++ b/CommandTerminal/CmdNetworkSessionKey.h
@@ -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__
diff --git a/CommandTerminal/CmdPublicNetwork.cpp b/CommandTerminal/CmdPublicNetwork.cpp
new file mode 100644
index 0000000..74bbeee
--- /dev/null
+++ b/CommandTerminal/CmdPublicNetwork.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdPublicNetwork.h b/CommandTerminal/CmdPublicNetwork.h
new file mode 100644
index 0000000..9efec06
--- /dev/null
+++ b/CommandTerminal/CmdPublicNetwork.h
@@ -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__
diff --git a/CommandTerminal/CmdSaveConfig.cpp b/CommandTerminal/CmdSaveConfig.cpp
new file mode 100644
index 0000000..712ba09
--- /dev/null
+++ b/CommandTerminal/CmdSaveConfig.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdSaveConfig.h b/CommandTerminal/CmdSaveConfig.h
new file mode 100644
index 0000000..dbf9671
--- /dev/null
+++ b/CommandTerminal/CmdSaveConfig.h
@@ -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__
diff --git a/CommandTerminal/CmdTxDataRate.cpp b/CommandTerminal/CmdTxDataRate.cpp
new file mode 100644
index 0000000..2d38f42
--- /dev/null
+++ b/CommandTerminal/CmdTxDataRate.cpp
@@ -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;
+}
diff --git a/CommandTerminal/CmdTxDataRate.h b/CommandTerminal/CmdTxDataRate.h
new file mode 100644
index 0000000..e848b9a
--- /dev/null
+++ b/CommandTerminal/CmdTxDataRate.h
@@ -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__
diff --git a/CommandTerminal/CmdTxPower.cpp b/CommandTerminal/CmdTxPower.cpp
new file mode 100644
index 0000000..8816b46
--- /dev/null
+++ b/CommandTerminal/CmdTxPower.cpp
@@ -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;
+}
+
diff --git a/CommandTerminal/CmdTxPower.h b/CommandTerminal/CmdTxPower.h
new file mode 100644
index 0000000..4b12b08
--- /dev/null
+++ b/CommandTerminal/CmdTxPower.h
@@ -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__
diff --git a/CommandTerminal/Command.cpp b/CommandTerminal/Command.cpp
new file mode 100644
index 0000000..5282f45
--- /dev/null
+++ b/CommandTerminal/Command.cpp
@@ -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;
+}
+
diff --git a/CommandTerminal/Command.h b/CommandTerminal/Command.h
new file mode 100644
index 0000000..bf46158
--- /dev/null
+++ b/CommandTerminal/Command.h
@@ -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****/
diff --git a/CommandTerminal/CommandTerminal.cpp b/CommandTerminal/CommandTerminal.cpp
new file mode 100644
index 0000000..65509bb
--- /dev/null
+++ b/CommandTerminal/CommandTerminal.cpp
@@ -0,0 +1,631 @@
+#include "ctype.h"
+#include "CommandTerminal.h"
+#include "Command.h"
+#include "MTSLog.h"
+#include <cstdarg>
+#include <deque>
+
+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),
+ _idle_thread(idle, NULL, osPriorityLow),
+ _sleep_standby(true),
+ _xbee_on_sleep(XBEE_ON_SLEEP),
+ _serial_up(false) {
+
+ _serialp = &serial;
+
+ addCommand(new CmdAttention(_dot));
+ addCommand(new CmdIdentification(_dot, serial));
+ addCommand(new CmdFactoryDefault(_dot));
+ addCommand(new CmdSaveConfig(_dot));
+ addCommand(new CmdDisplayConfig(_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 CmdNetworkJoinMode(_dot, serial));
+ addCommand(new CmdTxDataRate(_dot, serial));
+ addCommand(new CmdTxPower(_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()];
+
+ logDebug("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;
+ logDebug("Exit serial mode\r\n");
+ escape_timer.stop();
+ escape_buffer.clear();
+ write(done);
+ return;
+ }
+ }
+
+ if (_serial_up) {
+ serial_read_timer.start();
+ uint32_t timeout = _dot->getWakeDelay();
+
+ // wait for timeout or start of serial data
+ while (!readable() && serial_read_timer.read_ms() < timeout) {
+ osDelay(10);
+ }
+
+ serial_read_timer.reset();
+ timeout = _dot->getWakeTimeout();
+ while (_serial_up && serial_read_timer.read_ms() < timeout) {
+ 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;
+ logDebug("Received serial data, sending out radio.\r\n");
+
+ if (_dot->send(serial_buffer) != mDot::MDOT_OK)
+ logDebug("Send failed.\r\n");
+
+ if (_dot->recv(recv_buffer))
+ _serial.writef("%s\r\n", formatPacketData(recv_buffer, _dot->getRxOutput()).c_str());
+ } else {
+ logDebug("Radio is busy, cannot send.\r\n");
+ }
+
+ serial_buffer.clear();
+ } else {
+ logDebug("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;
+ logDebug("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() {
+
+ wakeup(_sleep_standby);
+
+ char ch;
+ bool running = true;
+ bool echo = _dot->getEcho();
+ std::string command;
+ std::deque<std::string> history;
+ int history_index = -1;
+ 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' || ch == 0x7f) {
+ if (!command.empty()) {
+ writef("\b \b");
+ command.erase(command.size() - 1);
+ }
+ continue;
+ } else if (ch == 0x1b || ch == 0x09) {
+ osDelay(20);
+ // catch escape sequence, or tab
+ char ch1, ch2;
+
+ if (readable()) {
+ ch1 = read();
+ if (readable())
+ ch2 = read();
+
+ if (ch1 == 0x5b && ch2 == 0x41) {
+ // up key
+ for (int i = 0; i < command.size()+1; i++) {
+ writef("\b \b");
+ }
+ if (history.size() > 0) {
+ if (++history_index >= history.size() - 1)
+ history_index = history.size() - 1;
+
+ command = history[history_index];
+ writef("%s", history[history_index].c_str());
+ } else {
+ command.clear();
+ }
+ } else if (ch1 == 0x5b && ch2 == 0x42) {
+
+ // down key
+ for (int i = 0; i < command.size()+1; i++) {
+ writef("\b \b");
+ }
+
+ if (--history_index < 0) {
+ history_index = -1;
+ command.clear();
+ } else {
+ command = history[history_index];
+ writef("%s", history[history_index].c_str());
+ }
+ }
+ }
+ while (readable()) read();
+ 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") {
+ logDebug("Enter Serial Mode\r\n");
+ _mode = mDot::SERIAL_MODE;
+ } else if (args[0] == "AT+SLEEP") {
+ if (args.size() > 1 && (args[1] != "?")) {
+ write("Invalid argument\r\n");
+ write(error);
+ } else {
+ if (args.size() > 1 && args[1] == "?") {
+ write("AT+SLEEP: NONE\r\n");
+ write(done);
+ } else {
+ _sleep_standby = !(args.size() > 1 && args[1] == "1");
+ this->sleep(_sleep_standby);
+ wait(0.1);
+ write(done);
+ }
+ }
+ } 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);
+ }
+ }
+
+ if (history.size() == 0 || history.front() != command)
+ history.push_front(command);
+ history_index = -1;
+ command.clear();
+
+ while (history.size() > 10)
+ history.pop_back();
+
+ }
+}
+
+std::string CommandTerminal::formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format) {
+ if (format == mDot::HEXADECIMAL)
+ return mts::Text::bin2hexString(data);
+ else
+ return std::string(data.begin(), data.end());
+}
+
+void CommandTerminal::sleep(bool standby) {
+ _serial_up = false;
+ _xbee_on_sleep = GPIO_PIN_RESET;
+
+ _serial.rxClear();
+ _serial.txClear();
+
+ _dot->sleep(_dot->getWakeInterval(), _dot->getWakeMode(), standby);
+}
+
+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) {
+
+}
diff --git a/CommandTerminal/CommandTerminal.h b/CommandTerminal/CommandTerminal.h
new file mode 100644
index 0000000..e64ec41
--- /dev/null
+++ b/CommandTerminal/CommandTerminal.h
@@ -0,0 +1,118 @@
+/**
+ ******************************************************************************
+ * 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:
+
+ static void idle(void const* args) {
+ while (1)
+ __WFI();
+ }
+
+ mts::MTSSerial& _serial;
+ static mts::MTSSerial* _serialp;
+
+ mDot* _dot;
+ mDot::Mode _mode;
+ std::vector<Command*> _commands;
+ Thread _idle_thread;
+ 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__
+
diff --git a/CommandTerminal/Commands.h b/CommandTerminal/Commands.h
new file mode 100644
index 0000000..5b699f4
--- /dev/null
+++ b/CommandTerminal/Commands.h
@@ -0,0 +1,19 @@
+#include "Command.h"
+
+#include "CmdAttention.h"
+#include "CmdIdentification.h"
+
+#include "CmdFactoryDefault.h"
+#include "CmdSaveConfig.h"
+#include "CmdDisplayConfig.h"
+#include "CmdDeviceId.h"
+#include "CmdPublicNetwork.h"
+#include "CmdNetworkAddress.h"
+#include "CmdNetworkSessionKey.h"
+#include "CmdDataSessionKey.h"
+#include "CmdNetworkKey.h"
+#include "CmdNetworkId.h"
+#include "CmdNetworkJoinMode.h"
+#include "CmdTxDataRate.h"
+#include "CmdTxPower.h"
+#include "CmdFrequencySubBand.h"
diff --git a/CommandTerminal/Test/TestCommandTerminal.h b/CommandTerminal/Test/TestCommandTerminal.h
new file mode 100644
index 0000000..0d5e801
--- /dev/null
+++ b/CommandTerminal/Test/TestCommandTerminal.h
@@ -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 */