diff options
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 */ | 
