![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
AT terminal for the mDot using the USB debug port instead of the serial port.
Dependencies: MTS-Serial libmDot-mbed5
Fork of Dot-AT-Firmware by
Diff: CommandTerminal/CommandTerminal.cpp
- Revision:
- 14:f9a77400b622
- Parent:
- 11:05e0f30c03a6
- Child:
- 16:d5cf2af81a6d
--- a/CommandTerminal/CommandTerminal.cpp Fri Nov 04 19:10:24 2016 +0000 +++ b/CommandTerminal/CommandTerminal.cpp Fri Nov 04 14:25:43 2016 -0500 @@ -4,8 +4,15 @@ #include "MTSLog.h" #include <cstdarg> #include <deque> +#if defined(TARGET_XDOT_L151CC) +#include "xdot_low_power.h" +#endif +#if defined(TARGET_MTS_MDOT_F411RE) const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa XBee Module\r\n\n"; +#else +const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa xDot Module\r\n\n"; +#endif const char CommandTerminal::helpline[] = "Enter '?' for help\r\n"; const char CommandTerminal::newline[] = "\r\n"; @@ -25,120 +32,372 @@ const char CommandTerminal::escape_sequence[] = "+++"; mts::ATSerial* CommandTerminal::_serialp = NULL; +mDot* CommandTerminal::_dot = NULL; + +CommandTerminal::RadioEvent* CommandTerminal::_events = new RadioEvent(); static bool serial_data_mode = false; static bool peer_to_peer = false; -void CommandTerminal::addCommand(Command* cmd) { - _commands.push_back(cmd); +std::string CommandTerminal::_errorMessage = ""; + +void CommandTerminal::setErrorMessage(const char* message) { + _errorMessage.assign(message); +} + +void CommandTerminal::setErrorMessage(const std::string& message) { + _errorMessage.assign(message); } -CommandTerminal::CommandTerminal(mts::ATSerial& serial, mDot* dot) -: - _serial(serial), - _dot(dot), - _events(new RadioEvent(serial)), - _mode(mDot::COMMAND_MODE), - _idle_thread(idle, NULL, osPriorityLow), - _sleep_standby(true), - _xbee_on_sleep(XBEE_ON_SLEEP) { +const Command CommandTerminal::_commands[NO_OF_COMMANDS] = { + CmdAttention(), + CmdIdentification(), + CmdResetCpu(), + CmdDummy("Enable/Disable Echo", "ATE", "ATE0: disable, ATE1: enable", "(0,1)"), + CmdDummy("Enable/Disable Verbose", "ATV", "ATV0: disable, ATV1: enable", "(0,1)"), + CmdDummy("Hardware Flow Control", "AT&K", "AT&K0: disable, AT&K3: enable", "(0,3)"), + + CmdFactoryDefault(), + CmdSaveConfig(), + CmdDisplayConfig(), + CmdDisplayStats(), + CmdResetStats(), + CmdSerialBaudRate(), + CmdDebugBaudRate(), + CmdStartUpMode(), + + CmdFrequencyBand(), + CmdFrequencySubBand(), + CmdPublicNetwork(), + CmdDeviceId(), + CmdDeviceClass(), + + CmdAppPort(), + CmdNetworkAddress(), + CmdNetworkSessionKey(), + CmdDataSessionKey(), + CmdUplinkCounter(), + CmdDownlinkCounter(), + CmdSaveSession(), + CmdRestoreSession(), + CmdNetworkKey(), + CmdNetworkId(), - _dot->setEvents(_events); - _dot->setWakeupCallback(this, &CommandTerminal::wakeup); - _serialp = &serial; + CmdJoinDelay(), +// Remove join settings commands until valid case for changing default settings +// CmdJoinRx1Offset(), +// CmdJoinRx2Datarate(), +// CmdJoinRx2Frequency(), + CmdJoinRequest(), + CmdJoinRetries(), + CmdJoinByteOrder(), + CmdNetworkJoinMode(), + CmdPreserveSession(), + CmdNetworkJoinStatus(), + CmdNetworkLinkCheck(), + CmdLinkCheckCount(), + CmdLinkCheckThreshold(), + CmdEncryption(), + + CmdRssi(), + CmdSnr(), + CmdDataPending(), + + CmdSessionDataRate(), + CmdChannelMask(), - addCommand(new CmdAttention(_dot)); - addCommand(new CmdIdentification(_dot, serial)); - addCommand(new CmdResetCpu(_dot, serial)); - addCommand(new CmdDummy(_dot, "Enable/Disable Echo", "ATE", "ATE0: disable, ATE1: enable")); - addCommand(new CmdDummy(_dot, "Enable/Disable Verbose", "ATV", "ATV0: disable, ATV1: enable")); - addCommand(new CmdDummy(_dot, "Hardware Flow Control", "AT&K", "AT&K0: disable, AT&K3: enable")); + CmdTxDataRate(), + CmdTxPower(), + CmdAntennaGain(), + CmdTxFrequency(), + CmdTxInverted(), + CmdTxWait(), + CmdTxChannel(), + CmdTxNextMs(), + CmdTimeOnAir(), + + CmdRxDelay(), + CmdRxOutput(), + CmdRxInverted(), + + CmdErrorCorrection(), + CmdCRC(), + CmdAdaptiveDataRate(), + + CmdACKAttempts(), + CmdRepeat(), + CmdMacCmd(), + + CmdSendString(), + CmdSendBinary(), + CmdReceiveOnce(), - addCommand(new CmdFactoryDefault(_dot)); - addCommand(new CmdSaveConfig(_dot)); - addCommand(new CmdDisplayConfig(_dot, serial)); - addCommand(new CmdDisplayStats(_dot, serial)); - addCommand(new CmdResetStats(_dot, serial)); - addCommand(new CmdSerialBaudRate(_dot, serial)); - addCommand(new CmdDebugBaudRate(_dot, serial)); - addCommand(new CmdStartUpMode(_dot, serial)); + CmdDummy("Serial Data Mode", "AT+SD", "Enter serial data mode, exit with '+++'", "NONE"), + CmdDummy("Sleep Mode", "AT+SLEEP", "Enter sleep mode (0:deepsleep,1:sleep)", "(0,1)"), + CmdSerialClearOnError(), + CmdWakeMode(), + CmdWakeInterval(), + CmdWakePin(), + CmdWakeDelay(), + CmdWakeTimeout(), + CmdPing(), + CmdLogLevel(), + + CmdDummy("***** Test Commands *****", "", "", ""), + CmdRxDataRate(), + CmdRxFrequency(), + CmdReceiveContinuous(), + CmdSendStringOnInterval(), + +#ifdef MTS_RADIO_DEBUG_COMMANDS + CmdDummy("***** Debug Commands *****", "", "", ""), + CmdSendContinuous(), + CmdWriteProtectedConfig(), + CmdDumpRegisters(), + CmdEraseFlash(), + CmdDisableDutyCycle(), +#endif + +}; + +const verify_ptr_t CommandTerminal::_verify[NO_OF_COMMANDS] = { + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, - addCommand(new CmdFrequencyBand(_dot, serial)); - addCommand(new CmdFrequencySubBand(_dot, serial)); - addCommand(new CmdPublicNetwork(_dot, serial)); - addCommand(new CmdDeviceId(_dot, serial)); - addCommand(new CmdDeviceClass(_dot, serial)); + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdSerialBaudRate::verify, + CmdDebugBaudRate::verify, + CmdStartUpMode::verify, + + CmdFrequencyBand::verify, + CmdFrequencySubBand::verify, + CmdPublicNetwork::verify, + CmdDeviceId::verify, + CmdDeviceClass::verify, - addCommand(new CmdAppPort(_dot, serial)); - addCommand(new CmdNetworkAddress(_dot, serial)); - addCommand(new CmdNetworkSessionKey(_dot, serial)); - addCommand(new CmdDataSessionKey(_dot, serial)); - addCommand(new CmdUplinkCounter(_dot, serial)); - addCommand(new CmdDownlinkCounter(_dot, serial)); - addCommand(new CmdSaveSession(_dot, serial)); - addCommand(new CmdRestoreSession(_dot, serial)); - addCommand(new CmdNetworkKey(_dot, serial)); - addCommand(new CmdNetworkId(_dot, serial)); + CmdAppPort::verify, + CmdNetworkAddress::verify, + CmdNetworkSessionKey::verify, + CmdDataSessionKey::verify, + CmdUplinkCounter::verify, + CmdDownlinkCounter::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdNetworkKey::verify, + CmdNetworkId::verify, + + CmdJoinDelay::verify, +// Remove join settings commands until valid case for changing default settings +// CmdJoinRx1Offset::verify, +// CmdJoinRx2Datarate::verify, +// CmdJoinRx2Frequency::verify, + CmdJoinRequest::verify, + CmdJoinRetries::verify, + CmdJoinByteOrder::verify, + CmdNetworkJoinMode::verify, + CmdPreserveSession::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdLinkCheckCount::verify, + CmdLinkCheckThreshold::verify, + CmdEncryption::verify, + + CmdDummy::verify, + CmdDummy::verify, + CmdDummy::verify, + + CmdSessionDataRate::verify, + CmdChannelMask::verify, - addCommand(new CmdJoinDelay(_dot, serial)); - addCommand(new CmdJoinRequest(_dot, serial)); - addCommand(new CmdJoinRetries(_dot, serial)); - addCommand(new CmdJoinByteOrder(_dot, serial)); - addCommand(new CmdNetworkJoinMode(_dot, serial)); - addCommand(new CmdPreserveSession(_dot, serial)); - addCommand(new CmdNetworkJoinStatus(_dot, serial)); - addCommand(new CmdNetworkLinkCheck(_dot, serial)); - addCommand(new CmdLinkCheckCount(_dot, serial)); - addCommand(new CmdLinkCheckThreshold(_dot, serial)); - addCommand(new CmdEncryption(_dot, serial)); + CmdTxDataRate::verify, + CmdTxPower::verify, + CmdAntennaGain::verify, + CmdTxFrequency::verify, + CmdTxInverted::verify, + CmdTxWait::verify, + CmdTxChannel::verify, + CmdTxNextMs::verify, + CmdTimeOnAir::verify, + + CmdRxDelay::verify, + CmdRxOutput::verify, + CmdRxInverted::verify, + + CmdErrorCorrection::verify, + CmdCRC::verify, + CmdAdaptiveDataRate::verify, + + CmdACKAttempts::verify, + CmdRepeat::verify, + CmdMacCmd::verify, + + CmdSendString::verify, + CmdSendBinary::verify, + CmdReceiveOnce::verify, + + CmdDummy::verify, + CmdDummy::verify, + CmdSerialClearOnError::verify, + CmdWakeMode::verify, + CmdWakeInterval::verify, + CmdWakePin::verify, + CmdWakeDelay::verify, + CmdWakeTimeout::verify, + CmdDummy::verify, + CmdLogLevel::verify, + + CmdDummy::verify, + CmdRxDataRate::verify, + CmdRxFrequency::verify, + CmdReceiveContinuous::verify, + CmdSendStringOnInterval::verify, - addCommand(new CmdRssi(_dot, serial)); - addCommand(new CmdSnr(_dot, serial)); - addCommand(new CmdDataPending(_dot, serial)); +#ifdef MTS_RADIO_DEBUG_COMMANDS + CmdDummy::verify, + CmdSendContinuous::verify, + CmdDummy::verify, + CmdDummy::verify, + CmdEraseFlash::verify, + CmdDisableDutyCycle::verify, +#endif - addCommand(new CmdSessionDataRate(_dot, serial)); +}; + +const action_ptr_t CommandTerminal::_action[NO_OF_COMMANDS] = { + CmdAttention::action, + CmdIdentification::action, + CmdResetCpu::action, + CmdDummy::action, + CmdDummy::action, + CmdDummy::action, - addCommand(new CmdTxDataRate(_dot, serial)); - addCommand(new CmdTxPower(_dot, serial)); - addCommand(new CmdAntennaGain(_dot, serial)); - addCommand(new CmdTxFrequency(_dot, serial)); - addCommand(new CmdTxInverted(_dot, serial)); - addCommand(new CmdTxWait(_dot, serial)); - addCommand(new CmdTxChannel(_dot, serial)); - addCommand(new CmdTxNextMs(_dot, serial)); - addCommand(new CmdTimeOnAir(_dot, serial)); + CmdFactoryDefault::action, + CmdSaveConfig::action, + CmdDisplayConfig::action, + CmdDisplayStats::action, + CmdResetStats::action, + CmdSerialBaudRate::action, + CmdDebugBaudRate::action, + CmdStartUpMode::action, + + CmdFrequencyBand::action, + CmdFrequencySubBand::action, + CmdPublicNetwork::action, + CmdDeviceId::action, + CmdDeviceClass::action, + + CmdAppPort::action, + CmdNetworkAddress::action, + CmdNetworkSessionKey::action, + CmdDataSessionKey::action, + CmdUplinkCounter::action, + CmdDownlinkCounter::action, + CmdSaveSession::action, + CmdRestoreSession::action, + CmdNetworkKey::action, + CmdNetworkId::action, - addCommand(new CmdRxDelay(_dot, serial)); - addCommand(new CmdRxOutput(_dot, serial)); - addCommand(new CmdRxInverted(_dot, serial)); + CmdJoinDelay::action, +// Remove join settings commands until valid case for changing default settings +// CmdJoinRx1Offset::action, +// CmdJoinRx2Datarate::action, +// CmdJoinRx2Frequency::action, + CmdJoinRequest::action, + CmdJoinRetries::action, + CmdJoinByteOrder::action, + CmdNetworkJoinMode::action, + CmdPreserveSession::action, + CmdNetworkJoinStatus::action, + CmdNetworkLinkCheck::action, + CmdLinkCheckCount::action, + CmdLinkCheckThreshold::action, + CmdEncryption::action, + + CmdRssi::action, + CmdSnr::action, + CmdDataPending::action, - addCommand(new CmdErrorCorrection(_dot, serial)); - addCommand(new CmdCRC(_dot, serial)); - addCommand(new CmdAdaptiveDataRate(_dot, serial)); + CmdSessionDataRate::action, + CmdChannelMask::action, - addCommand(new CmdACKAttempts(_dot, serial)); - addCommand(new CmdRepeat(_dot, serial)); + CmdTxDataRate::action, + CmdTxPower::action, + CmdAntennaGain::action, + CmdTxFrequency::action, + CmdTxInverted::action, + CmdTxWait::action, + CmdTxChannel::action, + CmdTxNextMs::action, + CmdTimeOnAir::action, - addCommand(new CmdSendString(_dot, serial)); - addCommand(new CmdSendBinary(_dot, serial)); - addCommand(new CmdReceiveOnce(_dot, serial)); + CmdRxDelay::action, + CmdRxOutput::action, + CmdRxInverted::action, + + CmdErrorCorrection::action, + CmdCRC::action, + CmdAdaptiveDataRate::action, + + CmdACKAttempts::action, + CmdRepeat::action, + CmdMacCmd::action, - addCommand(new CmdDummy(_dot, "Serial Data Mode", "AT+SD", "Enter serial data mode, exit with '+++'")); - addCommand(new CmdDummy(_dot, "Sleep Mode", "AT+SLEEP", "Enter sleep mode (0:deepsleep,1:sleep)")); - addCommand(new CmdSerialClearOnError(_dot, serial)); - addCommand(new CmdWakeMode(_dot, serial)); - addCommand(new CmdWakeInterval(_dot, serial)); - addCommand(new CmdWakePin(_dot, serial)); - addCommand(new CmdWakeDelay(_dot, serial)); - addCommand(new CmdWakeTimeout(_dot, serial)); - addCommand(new CmdPing(_dot, serial)); - addCommand(new CmdLogLevel(_dot, serial)); + CmdSendString::action, + CmdSendBinary::action, + CmdReceiveOnce::action, + + CmdDummy::action, + CmdDummy::action, + CmdSerialClearOnError::action, + CmdWakeMode::action, + CmdWakeInterval::action, + CmdWakePin::action, + CmdWakeDelay::action, + CmdWakeTimeout::action, + CmdPing::action, + CmdLogLevel::action, + + CmdDummy::action, + CmdRxDataRate::action, + CmdRxFrequency::action, + CmdReceiveContinuous::action, + CmdSendStringOnInterval::action, - addCommand(new CmdDummy(_dot, "***** Test Commands *****", "", "")); - addCommand(new CmdRxDataRate(_dot, serial)); - addCommand(new CmdRxFrequency(_dot, serial)); - addCommand(new CmdReceiveContinuous(_dot, serial)); - addCommand(new CmdSendStringOnInterval(_dot, serial)); +#ifdef MTS_RADIO_DEBUG_COMMANDS + CmdDummy::action, + CmdSendContinuous::action, + CmdWriteProtectedConfig::action, + CmdDumpRegisters::action, + CmdEraseFlash::action, + CmdDisableDutyCycle::action, +#endif + +}; + +CommandTerminal::CommandTerminal(mts::ATSerial& serial) : + _serial(serial), + _mode(mDot::COMMAND_MODE), + _sleep_standby(true), +#if defined(TARGET_MTS_MDOT_F411RE) + _xbee_on_sleep(XBEE_ON_SLEEP), +#else + _xbee_on_sleep(GPIO2), +#endif + _autoOTAEnabled(false) +{ + _serialp = &serial; +} + +void CommandTerminal::init() { + _dot->setEvents(_events); } void CommandTerminal::printHelp() { @@ -160,10 +419,11 @@ 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(); + + for (int i = 0; i < NO_OF_COMMANDS; i++) { + name = _commands[i].name(); + text = _commands[i].text(); + desc = _commands[i].desc(); write(text); if (strlen(text) < 8) write(tab); @@ -182,23 +442,23 @@ } bool CommandTerminal::writeable() { - return _serial.writeable(); + return _serialp->writeable(); } bool CommandTerminal::readable() { - return _serial.readable(); + return _serialp->readable(); } char CommandTerminal::read() { char ch; - _serial.read(&ch, 1); + _serialp->read(&ch, 1); return ch; } void CommandTerminal::write(const char* message) { while (!writeable()) ; - _serial.write(message, strlen(message)); + _serialp->write(message, strlen(message)); } void CommandTerminal::writef(const char* format, ...) { @@ -209,7 +469,7 @@ int size = vsnprintf(buff, 256, format, ap); while (!writeable()) ; - _serial.write(buff, size); + _serialp->write(buff, size); va_end(ap); } @@ -227,12 +487,17 @@ timeout = _dot->getWakeDelay(); // wait for timeout or start of serial data - while (!readable() && serial_read_timer.read_ms() < timeout && !_serial.escaped()) { + while (!readable() && serial_read_timer.read_ms() < timeout && !_serialp->escaped()) { osDelay(2); } } - if (readable() && !_serial.escaped()) { + if (!readable() && _events->SendAck()) { + logDebug("SERIAL NOT READABLE and ACK REQUESTED"); + goto L_SEND; + } + + if (readable() && !_serialp->escaped()) { serial_read_timer.reset(); timeout = _dot->getWakeTimeout(); @@ -242,7 +507,7 @@ serial_buffer.push_back(read()); serial_read_timer.reset(); - if (_serial.escaped()) + if (_serialp->escaped()) break; } } @@ -251,14 +516,15 @@ if (!serial_buffer.empty()) { if (_dot->getStartUpMode() == mDot::SERIAL_MODE) - _xbee_on_sleep = GPIO_PIN_RESET; + _xbee_on_sleep = GPIO_PIN_RESET; +L_SEND: // wait for any duty cycle limit to expire - while (_dot->getNextTxMs() > 0 && !_serial.escaped()) { + while (_dot->getNextTxMs() > 0 && !_serialp->escaped()) { osDelay(10); } - if (!_dot->getIsTransmitting()) { + if (_dot->getIsIdle()) { logDebug("Received serial data, sending out radio."); if (_dot->send(serial_buffer, false) != mDot::MDOT_OK) { @@ -270,15 +536,28 @@ } else { // wait for send to finish - while (_dot->getIsTransmitting() && !_serial.escaped()) + while (!_dot->getIsIdle() && !_serialp->escaped()) { osDelay(10); + } // call recv to wait for any packet before sending again - if (!_serial.escaped()) + if (!_serialp->escaped()) _dot->recv(data); // Clear the serial buffer if send is success serial_buffer.clear(); + + // In class C mode pending data will be sent automatically without uplink + if (_dot->getClass() != "C") { + if (_dot->getDataPending()) { + logDebug("Data is pending"); + goto L_SEND; + } + if (_dot->getAckRequested()) { + logDebug("Ack requested"); + goto L_SEND; + } + } } } else { logDebug("Radio is busy, cannot send.\r\n"); @@ -290,14 +569,13 @@ } } - if (!_serial.readable() && _dot->getStartUpMode() == mDot::SERIAL_MODE && !_serial.escaped()) { - _xbee_on_sleep = GPIO_PIN_RESET; - sleep(_sleep_standby); + if (!_serialp->readable() && _dot->getStartUpMode() == mDot::SERIAL_MODE && !_serialp->escaped()) { + sleep(true); } - if (_serial.escaped()) { - _serial.clearEscaped(); - _serial.rxClear(); + if (_serialp->escaped()) { + _serialp->clearEscaped(); + _serialp->rxClear(); serial_data_mode = false; _mode = mDot::COMMAND_MODE; logDebug("Exit Serial Mode"); @@ -323,42 +601,46 @@ int cnt = 0; while (!_dot->getNetworkJoinStatus()) { - write("\r\nJoining network... "); + if (!serial_data_mode) { + write("\r\nJoining network... "); + } + logInfo("Joining network... "); if (_dot->getNextTxMs() > 0) { - int rand_time = rand() % 10000; - writef("\r\nWaiting %lu s before next join attempt\r\n", (_dot->getNextTxMs() + rand_time) / 1000); + if (!serial_data_mode) { + writef("\r\nWaiting %lu s before next join attempt\r\n", _dot->getNextTxMs() / 1000); + } + logInfo("Waiting %lu s before next join attempt", _dot->getNextTxMs() / 1000); tmr.reset(); while (_dot->getNextTxMs() > 0 && !_serial.escaped()) { - osDelay(2); + osDelay(20); } - - tmr.reset(); - while (tmr.read_ms() < rand_time && !_serial.escaped()) - osDelay(10); } if (!_serial.escaped() && _dot->joinNetworkOnce() == mDot::MDOT_OK) { - write("Network Joined\r\n"); - write(done); + if (!serial_data_mode) { + write("Network Joined\r\n"); + write(done); + } + logInfo("Network Joined"); return false; } - write("Network Join failed\r\n"); - write(error); + if (!serial_data_mode) { + write("Network Join failed\r\n"); + write(error); + } + logInfo("Network Join failed"); - if (!_serial.escaped() && _dot->getJoinRetries() > 0 && cnt++ > _dot->getJoinRetries()) { + if (!_serial.escaped() && _dot->getFrequencySubBand() != 0 && _dot->getJoinRetries() > 0 && cnt++ > _dot->getJoinRetries()) { cnt = 0; - if (_dot->getFrequencyBand() == mDot::FB_915) { + if (_dot->getFrequencyBand() == mDot::FB_US915 || _dot->getFrequencyBand() == mDot::FB_AU915 ) { uint8_t band = ((_dot->getFrequencySubBand()) % 8) + 1; logWarning("Join retries exhausted, switching to sub band %u", band); _dot->setFrequencySubBand(band); } - - if (sleep < 60 * 60 * 1000) - sleep *= 2; } tmr.reset(); @@ -370,8 +652,11 @@ _serial.clearEscaped(); serial_data_mode = false; _mode = mDot::COMMAND_MODE; - write("Join Canceled\r\n"); - write(done); + if (!serial_data_mode) { + write("Join Canceled\r\n"); + write(done); + } + logInfo("Join Canceled\r\n"); return true; } } @@ -385,11 +670,15 @@ bool running = true; bool echo = _dot->getEcho(); std::string command; +#if defined(TARGET_MTS_MDOT_F411RE) std::deque<std::string> history; int history_index = -1; +#endif std::vector<std::string> args; bool join_canceled = false; + _autoOTAEnabled = _dot->getJoinMode() == mDot::AUTO_OTA; + if (_dot->getStartUpMode() == mDot::SERIAL_MODE) { serial_data_mode = true; @@ -450,20 +739,18 @@ peer_to_peer = false; } - - //Run terminal session while (running) { // wait for input to reduce at command idle current while (!readable() || _mode == mDot::SERIAL_MODE) { - if (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA) { + if (!join_canceled && _autoOTAEnabled) { join_canceled = autoJoinCheck(); if (join_canceled) command.clear(); } - if (_dot->getJoinMode() != mDot::AUTO_OTA || (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA)) { + if (!_autoOTAEnabled || (!join_canceled && _autoOTAEnabled)) { switch (_mode) { case mDot::SERIAL_MODE: // signal wakeup, read serial and output to radio @@ -501,6 +788,7 @@ if (readable()) ch2 = read(); +#if defined(TARGET_MTS_MDOT_F411RE) if (ch1 == 0x5b && ch2 == 0x41) { // up key for (size_t i = 0; i < command.size() + 1; i++) { @@ -530,6 +818,7 @@ writef("%s", history[history_index].c_str()); } } +#endif } while (readable()) read(); @@ -639,9 +928,20 @@ write(done); } else { _sleep_standby = !(args.size() > 1 && args[1] == "1"); +#if defined(TARGET_MTS_MDOT_F411RE) + //Read the board ID. If all 0's, it is revision B. This hardware does not support deep sleep. + DigitalIn ID2(PC_4); + DigitalIn ID1(PC_5); + DigitalIn ID0(PD_2); + if(ID2 == 0 && ID1 == 0 && ID0 == 0 && _sleep_standby == 1){ + _sleep_standby = 0; + logWarning("This hardware version does not support deep sleep. Using sleep mode instead."); + } +#endif write(done); + osDelay(5); this->sleep(_sleep_standby); - wait(0.1); + osDelay(1); } } } else { @@ -661,28 +961,27 @@ } // search for command - for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) { - Command* cmd = *it; + for (int i = 0; i < NO_OF_COMMANDS; i++) { // match CMD or CMD? syntax if command is queryable - if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) { + if (lookfor == _commands[i].text() && (!query || (query && _commands[i].queryable()))) { found = true; if (args[0] == "HELP") { - writef("%s%s", cmd->help(), newline); + writef("%s%s", _commands[i].help().c_str(), newline); write(done); } else if (args.size() > 1 && args[1] == "?") { - writef("%s%s", cmd->usage().c_str(), newline); + writef("%s%s", _commands[i].usage().c_str(), newline); write(done); - } else if (!cmd->verify(args)) { - writef("%s%s", cmd->errorMessage().c_str(), newline); + } else if (!_verify[i](args)) { + writef("%s%s", _errorMessage.c_str(), newline); writef("%s", error); } else { - if (cmd->action(args) == 0) { + if (_action[i](args) == 0) { writef("%s", done); } else { - writef("%s%s", cmd->errorMessage().c_str(), newline); + writef("%s%s", _errorMessage.c_str(), newline); writef("%s", error); } } @@ -695,6 +994,7 @@ } } +#if defined(TARGET_MTS_MDOT_F411RE) if (history.size() == 0 || history.front() != command) history.push_front(command); history_index = -1; @@ -702,23 +1002,271 @@ while (history.size() > 10) history.pop_back(); +#else + command.clear(); +#endif } } -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) { _xbee_on_sleep = GPIO_PIN_RESET; _serial.rxClear(); _serial.txClear(); +#if defined(TARGET_XDOT_L151CC) + xdot_save_gpio_state(); + + /* GPIO Ports Clock Enable */ + __GPIOA_CLK_ENABLE(); + __GPIOB_CLK_ENABLE(); + __GPIOC_CLK_ENABLE(); + __GPIOH_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStruct; + + // UART1_TX, UART1_RTS & UART1_CTS to analog nopull - RX could be a wakeup source + GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // I2C_SDA & I2C_SCL to analog nopull + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // SPI_MOSI, SPI_MISO, SPI_SCK, & SPI_NSS to analog nopull + GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // iterate through potential wake pins - leave the configured wake pin alone if one is needed + if (_dot->getWakePin() != WAKE || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + if (_dot->getWakePin() != GPIO0 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + if (_dot->getWakePin() != GPIO1 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_5; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + if (_dot->getWakePin() != GPIO2 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } + if (_dot->getWakePin() != GPIO3 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } + if (_dot->getWakePin() != UART1_RX || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } +#else + uint32_t portA[6]; + uint32_t portB[6]; + uint32_t portC[6]; + uint32_t portD[6]; + uint32_t portH[6]; + + //Save the GPIO state. + portA[0] = GPIOA->MODER; + portA[1] = GPIOA->OTYPER; + portA[2] = GPIOA->OSPEEDR; + portA[3] = GPIOA->PUPDR; + portA[4] = GPIOA->AFR[0]; + portA[5] = GPIOA->AFR[1]; + + portB[0] = GPIOB->MODER; + portB[1] = GPIOB->OTYPER; + portB[2] = GPIOB->OSPEEDR; + portB[3] = GPIOB->PUPDR; + portB[4] = GPIOB->AFR[0]; + portB[5] = GPIOB->AFR[1]; + + portC[0] = GPIOC->MODER; + portC[1] = GPIOC->OTYPER; + portC[2] = GPIOC->OSPEEDR; + portC[3] = GPIOC->PUPDR; + portC[4] = GPIOC->AFR[0]; + portC[5] = GPIOC->AFR[1]; + + portD[0] = GPIOD->MODER; + portD[1] = GPIOD->OTYPER; + portD[2] = GPIOD->OSPEEDR; + portD[3] = GPIOD->PUPDR; + portD[4] = GPIOD->AFR[0]; + portD[5] = GPIOD->AFR[1]; + + portH[0] = GPIOH->MODER; + portH[1] = GPIOH->OTYPER; + portH[2] = GPIOH->OSPEEDR; + portH[3] = GPIOH->PUPDR; + portH[4] = GPIOH->AFR[0]; + portH[5] = GPIOH->AFR[1]; + + /* GPIO Ports Clock Enable */ + __GPIOA_CLK_ENABLE(); + __GPIOB_CLK_ENABLE(); + __GPIOC_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStruct; + + // Set port A pins to analog nopull + GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 + | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // Set port B pins to analog nopull + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // Set port C pins to analog nopull + GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_13; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + // iterate through potential wake pins - leave the configured wake pin alone if one is needed + // XBEE_DIN - PA3 + // XBEE_DIO2 - PA5 + // XBEE_DIO3 - PA4 + // XBEE_DIO4 - PA7 + // XBEE_DIO5 - PC1 + // XBEE_DIO6 - PA1 + // XBEE_DIO7 - PA0 + // XBEE_SLEEPRQ - PA11 + + if (_dot->getWakePin() != XBEE_DIN || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO2 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_5; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO3 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO4 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO5 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO6 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_DIO7 || _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + if (_dot->getWakePin() != XBEE_SLEEPRQ|| _dot->getWakeMode() == mDot::RTC_ALARM) { + GPIO_InitStruct.Pin = GPIO_PIN_11; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + +#endif _dot->sleep(_dot->getWakeInterval(), _dot->getWakeMode(), standby); + +#if defined(TARGET_XDOT_L151CC) + xdot_restore_gpio_state(); +#else + //Restore the GPIO state. + GPIOA->MODER = portA[0]; + GPIOA->OTYPER = portA[1]; + GPIOA->OSPEEDR = portA[2]; + GPIOA->PUPDR = portA[3]; + GPIOA->AFR[0] = portA[4]; + GPIOA->AFR[1] = portA[5]; + + GPIOB->MODER = portB[0]; + GPIOB->OTYPER = portB[1]; + GPIOB->OSPEEDR = portB[2]; + GPIOB->PUPDR = portB[3]; + GPIOB->AFR[0] = portB[4]; + GPIOB->AFR[1] = portB[5]; + + GPIOC->MODER = portC[0]; + GPIOC->OTYPER = portC[1]; + GPIOC->OSPEEDR = portC[2]; + GPIOC->PUPDR = portC[3]; + GPIOC->AFR[0] = portC[4]; + GPIOC->AFR[1] = portC[5]; + + GPIOD->MODER = portD[0]; + GPIOD->OTYPER = portD[1]; + GPIOD->OSPEEDR = portD[2]; + GPIOD->PUPDR = portD[3]; + GPIOD->AFR[0] = portD[4]; + GPIOD->AFR[1] = portD[5]; + + GPIOH->MODER = portH[0]; + GPIOH->OTYPER = portH[1]; + GPIOH->OSPEEDR = portH[2]; + GPIOH->PUPDR = portH[3]; + GPIOH->AFR[0] = portH[4]; + GPIOH->AFR[1] = portH[5]; +#endif + + _serial.rxClear(); + _serial.txClear(); +} + +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()); } bool CommandTerminal::waitForEscape(int timeout, mDot* dot, WaitType wait) { @@ -745,59 +1293,18 @@ } void CommandTerminal::wakeup(void) { - if (_dot->getWakePin() == XBEE_DIN) { - _serial.reattach(XBEE_DOUT, XBEE_DIN); - logInfo("Wakeup pin was serial input"); - } } -void CommandTerminal::RadioEvent::MacEvent(LoRaMacEventFlags* flags, LoRaMacEventInfo* info) { +void CommandTerminal::RadioEvent::PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries) { + mDotEvent::PacketRx(port, payload, size, rssi, snr, ctrl, retries); - if (mts::MTSLog::getLogLevel() == mts::MTSLog::TRACE_LEVEL) { - std::string msg = "OK"; - switch (info->Status) { - case LORAMAC_EVENT_INFO_STATUS_ERROR: - msg = "ERROR"; - break; - case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: - msg = "TX_TIMEOUT"; - break; - case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT: - msg = "RX_TIMEOUT"; - break; - case LORAMAC_EVENT_INFO_STATUS_RX_ERROR: - msg = "RX_ERROR"; - break; - case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL: - msg = "JOIN_FAIL"; - break; - case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_FAIL: - msg = "DOWNLINK_FAIL"; - break; - case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL: - msg = "ADDRESS_FAIL"; - break; - case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL: - msg = "MIC_FAIL"; - break; - default: - break; + if (serial_data_mode) { + logDebug("Rx %d bytes", size); + if (size > 0) { + CommandTerminal::Serial()->write((char*) RxPayload, RxPayloadSize); } - logTrace("Event: %s", msg.c_str()); - - logTrace("Flags Tx: %d Rx: %d RxData: %d RxSlot: %d LinkCheck: %d JoinAccept: %d", - flags->Bits.Tx, flags->Bits.Rx, flags->Bits.RxData, flags->Bits.RxSlot, flags->Bits.LinkCheck, flags->Bits.JoinAccept); - logTrace("Info: Status: %d ACK: %d Retries: %d TxDR: %d RxPort: %d RxSize: %d RSSI: %d SNR: %d Energy: %d Margin: %d Gateways: %d", - info->Status, info->TxAckReceived, info->TxNbRetries, info->TxDatarate, info->RxPort, info->RxBufferSize, - info->RxRssi, info->RxSnr, info->Energy, info->DemodMargin, info->NbGateways); - } - - if (flags->Bits.Rx) { - if (serial_data_mode) { - logDebug("Rx %d bytes", info->RxBufferSize); - if (info->RxBufferSize > 0) { - _serial.write((char*) info->RxBuffer, info->RxBufferSize); - } + if (!CommandTerminal::Serial()->readable() && _dot->getAckRequested() && _dot->getClass() == "C") { + _sendAck = true; } } }