![](/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
CommandTerminal/CommandTerminal.cpp
- Committer:
- Mike Fiore
- Date:
- 2015-07-10
- Revision:
- 2:e5eebd74d36d
- Parent:
- 1:e52ae6584f1c
- Child:
- 4:666017851052
File content as of revision 2:e5eebd74d36d:
#include "ctype.h" #include "CommandTerminal.h" #include "Command.h" #include <cstdarg> extern "C" { #include "wakeup.h" extern void pin_function(PinName pin, int data); } const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa XBee Module\r\n\n"; const char CommandTerminal::helpline[] = "Enter '?' for help\r\n"; const char CommandTerminal::newline[] = "\r\n"; // Command error text... const char CommandTerminal::command_error[] = "Command not found!\r\n"; // Response texts... const char CommandTerminal::help[] = "\r\nHelp\r\n"; const char CommandTerminal::cmd_error[] = "Invalid command\r\n"; const char CommandTerminal::done[] = "\r\nOK\r\n"; const char CommandTerminal::error[] = "\r\nERROR\r\n"; // Escape sequence... const char CommandTerminal::escape_sequence[] = "+++"; mts::MTSSerial* CommandTerminal::_serialp = NULL; void CommandTerminal::addCommand(Command* cmd) { _commands.push_back(cmd); } CommandTerminal::CommandTerminal(mts::MTSSerial& serial, mDot* dot) : _serial(serial), _dot(dot), _mode(mDot::COMMAND_MODE), _sleep_standby(false), _xbee_on_sleep(XBEE_ON_SLEEP), _serial_up(false) { _serialp = &serial; wakeup_init(_dot->getSerialWakeInterval()); addCommand(new CmdAttention(_dot)); addCommand(new CmdIdentification(_dot, serial)); addCommand(new CmdResetCpu(_dot, serial)); addCommand(new CmdDummy(_dot, "Enable/Disable Echo", "ATE0/1", "ATE0: disable, ATE1: enable")); addCommand(new CmdDummy(_dot, "Enable/Disable Verbose", "ATV0/1", "ATV0: disable, ATV1: enable")); addCommand(new CmdFactoryDefault(_dot)); addCommand(new CmdSaveConfig(_dot)); addCommand(new CmdDisplayConfig(_dot, serial)); addCommand(new CmdDisplayStats(_dot, serial)); addCommand(new CmdSerialBaudRate(_dot, serial)); addCommand(new CmdDebugBaudRate(_dot, serial)); addCommand(new CmdStartUpMode(_dot, serial)); addCommand(new CmdFrequencyBand(_dot, serial)); addCommand(new CmdFrequencySubBand(_dot, serial)); addCommand(new CmdPublicNetwork(_dot, serial)); addCommand(new CmdDeviceId(_dot, serial)); addCommand(new CmdNetworkAddress(_dot, serial)); addCommand(new CmdNetworkSessionKey(_dot, serial)); addCommand(new CmdDataSessionKey(_dot, serial)); addCommand(new CmdNetworkKey(_dot, serial)); addCommand(new CmdNetworkId(_dot, serial)); addCommand(new CmdJoinRequest(_dot, serial)); addCommand(new CmdJoinRetries(_dot, serial)); addCommand(new CmdNetworkJoinMode(_dot, serial)); addCommand(new CmdNetworkJoinStatus(_dot, serial)); addCommand(new CmdNetworkLinkCheck(_dot, serial)); addCommand(new CmdLinkCheckCount(_dot, serial)); addCommand(new CmdLinkCheckThreshold(_dot, serial)); addCommand(new CmdEncryption(_dot, serial)); addCommand(new CmdRssi(_dot, serial)); addCommand(new CmdSnr(_dot, serial)); addCommand(new CmdDataPending(_dot, serial)); addCommand(new CmdTxDataRate(_dot, serial)); addCommand(new CmdTxPower(_dot, serial)); addCommand(new CmdTxFrequency(_dot, serial)); addCommand(new CmdTxInverted(_dot, serial)); addCommand(new CmdTxWait(_dot, serial)); addCommand(new CmdTxChannel(_dot, serial)); addCommand(new CmdTxNextMs(_dot, serial)); addCommand(new CmdTimeOnAir(_dot, serial)); addCommand(new CmdRxDataRate(_dot, serial)); addCommand(new CmdRxFrequency(_dot, serial)); addCommand(new CmdRxOutput(_dot, serial)); addCommand(new CmdRxInverted(_dot, serial)); addCommand(new CmdErrorCorrection(_dot, serial)); addCommand(new CmdCRC(_dot, serial)); addCommand(new CmdAdaptiveDataRate(_dot, serial)); addCommand(new CmdACKAttempts(_dot, serial)); addCommand(new CmdSendString(_dot, serial)); addCommand(new CmdSendStringHighBW(_dot, serial)); addCommand(new CmdSendBinary(_dot, serial)); addCommand(new CmdSendStringOnInterval(_dot, serial)); addCommand(new CmdReceiveOnce(_dot, serial)); addCommand(new CmdReceiveContinuous(_dot, serial)); addCommand(new CmdDummy(_dot, "Serial Data Mode", "AT+SD", "Reads serial data and sends Lora packets (escape sequence: +++)")); addCommand(new CmdSerialWakeInterval(_dot, serial)); addCommand(new CmdSerialWakeDelay(_dot, serial)); addCommand(new CmdSerialReceiveTimeout(_dot, serial)); addCommand(new CmdPing(_dot, serial)); addCommand(new CmdLogLevel(_dot, serial)); } void CommandTerminal::printHelp() { const char* name = NULL; const char* text = NULL; const char* desc = NULL; const char* tab = "\t"; std::string header("Command"); header.append(tab); header.append(tab); header.append("Name"); header.append(tab); header.append(tab); header.append(tab); header.append("Description"); write(newline); write(header.c_str()); write(newline); write(newline); for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) { name = (*it)->name(); text = (*it)->text(); desc = (*it)->desc(); write(text); if (strlen(text) < 8) write(tab); write(tab); write(name); if (strlen(name) < 8) write(tab); if (strlen(name) < 16) write(tab); write(tab); write(desc); write(newline); } write(newline); } bool CommandTerminal::writeable() { return _serial.writeable(); } bool CommandTerminal::readable() { return _serial.readable(); } char CommandTerminal::read() { char ch; _serial.read(&ch, 1); return ch; } void CommandTerminal::write(const char* message) { while (!writeable()) ; _serial.write(message, strlen(message)); } void CommandTerminal::writef(const char* format, ...) { char buff[256]; va_list ap; va_start(ap, format); int size = vsnprintf(buff, 256, format, ap); while (!writeable()) ; _serial.write(buff, size); va_end(ap); } void CommandTerminal::serial_loop() { Timer serial_read_timer; std::vector<uint8_t> serial_buffer; std::string escape_buffer; Timer escape_timer; int escape_delay = 100; uint8_t max_send_size; _serial_up = true; _xbee_on_sleep = GPIO_PIN_SET; if (_dot->getFrequencyBand() == mDot::FB_915) max_send_size = mDot::MaxLengths_915[_dot->getTxDataRate()]; else max_send_size = mDot::MaxLengths_868[_dot->getTxDataRate()]; DEBUG_PRINTF("Awake\r\n"); wakeup(_sleep_standby); char ch; if (readable()) { ch = read(); serial_buffer.push_back(ch); if (escape_timer.read_ms() > escape_delay && ch == '+') { escape_buffer += ch; escape_timer.reset(); } else { _serial_up = true; escape_buffer.clear(); } if (escape_buffer.length() == 3 && escape_buffer.find(escape_sequence) == 0) { _mode = mDot::COMMAND_MODE; DEBUG_PRINTF("Exit serial mode\r\n"); escape_timer.stop(); escape_buffer.clear(); write(done); return; } } if (_serial_up) { osDelay(_dot->getSerialWakeDelay()); serial_read_timer.start(); while (_serial_up && serial_read_timer.read_ms() < _dot->getSerialReceiveTimeout()) { while (readable() && serial_buffer.size() < max_send_size) { serial_buffer.push_back(read()); serial_read_timer.reset(); } } serial_read_timer.stop(), serial_read_timer.reset(); if (!serial_buffer.empty()) { _serial_up = false; _xbee_on_sleep = GPIO_PIN_RESET; if (!_dot->getIsTransmitting()) { std::vector<uint8_t> recv_buffer; DEBUG_PRINTF("Received serial data, sending out radio.\r\n"); if (!_dot->send(serial_buffer)) DEBUG_PRINTF("Send failed.\r\n"); if (_dot->recv(recv_buffer)) _serial.writef("%s\r\n", formatPacketData(recv_buffer, _dot->getRxOutput()).c_str()); } else { DEBUG_PRINTF("Radio is busy, cannot send.\r\n"); } serial_buffer.clear(); } else { DEBUG_PRINTF("No data received from serial to send.\r\n"); } _serial_up = false; } sleep(_sleep_standby); } bool CommandTerminal::autoJoinCheck() { std::string escape_buffer; char ch; int sleep = 1000; int escape_timeout = 1000; Timer tmr; Timer escape_tmr; int cnt = 0; while (!_dot->getNetworkJoinStatus()) { wakeup(_sleep_standby); write("\r\nJoining network... "); // wait one second for possible escape tmr.reset(); tmr.start(); escape_tmr.reset(); escape_tmr.start(); while (tmr.read_ms() < 1000) { if (_serial.readable()) { _serial.read(&ch, 1); escape_buffer += ch; } if (escape_buffer.find(escape_sequence) != std::string::npos) { _mode = mDot::COMMAND_MODE; write("Join Canceled\r\n"); write(done); return true; } if (escape_tmr.read_ms() > escape_timeout) escape_buffer.clear(); } if (_dot->joinNetworkOnce() == mDot::MDOT_OK) { write("Network Joined\r\n"); write(done); return false; } write("Network Join failed\r\n"); write(error); if (cnt++ > _dot->getJoinRetries()) { cnt = 0; if (_dot->getFrequencyBand() == mDot::FB_915) { uint8_t band = ((_dot->getFrequencySubBand()) % 8) + 1; DEBUG_PRINTF("Join retries exhausted, switching to sub band %u\r\n", band); _dot->setFrequencySubBand(band); } if (sleep < 60 * 60 * 1000) sleep *= 2; } tmr.reset(); tmr.start(); escape_tmr.reset(); escape_tmr.start(); while (tmr.read_ms() < sleep) { if (_serial.readable()) { _serial.read(&ch, 1); escape_buffer += ch; } if (escape_buffer.find(escape_sequence) != std::string::npos) { _mode = mDot::COMMAND_MODE; return true; } if (escape_tmr.read_ms() > escape_timeout) escape_buffer.clear(); } } return false; } void CommandTerminal::start() { _dot->resetNetworkSession(); char ch; bool running = true; bool echo = _dot->getEcho(); std::string command; std::vector<std::string> args; if (_dot->getStartUpMode() == mDot::SERIAL_MODE) { command = "AT+SD\n"; std::string escape_buffer; char ch; int escape_timeout = 1000; Timer tmr; Timer escape_tmr; // wait one second for possible escape tmr.reset(); tmr.start(); escape_tmr.reset(); escape_tmr.start(); while (tmr.read_ms() < escape_timeout) { if (_serial.readable()) { _serial.read(&ch, 1); escape_buffer += ch; } if (escape_buffer.find(escape_sequence) != std::string::npos) { _mode = mDot::COMMAND_MODE; command.clear(); break; } if (escape_tmr.read_ms() > escape_timeout) escape_buffer.clear(); osDelay(1); } } bool join_canceled = false; //Run terminal session while (running) { if (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA) { join_canceled = autoJoinCheck(); if (join_canceled) command.clear(); } if (_dot->getJoinMode() != mDot::AUTO_OTA || (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA)) { switch (_mode) { case mDot::SERIAL_MODE: // signal wakeup, read serial and output to radio serial_loop(); continue; break; default: break; } } ch = '\0'; // read characters if (readable()) { ch = read(); if (ch == '\b') { if (!command.empty()) { writef("\b \b"); command.erase(command.size() - 1); } continue; } else { command += ch; } // echo chars if enabled if (echo && !(ch == '\r' || ch == '\n')) writef("%c", ch); } // look for end of command line if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) { // remove new line or cr character command.erase(command.size() - 1); write("\r"); // match standard modem output write(newline); } else { continue; } // trim whitespace from command mts::Text::trim(command, "\r\n\t "); if (command.size() < 1) { command.clear(); continue; } // parse command and args args.clear(); // find first '=' character size_t delim_index = command.find("="); if (delim_index != std::string::npos) { args.push_back(command.substr(0, delim_index)); } else { // find first ' ' character delim_index = command.find(" "); if (delim_index != std::string::npos) { args.push_back(command.substr(0, delim_index)); } else { args.push_back(command); } } if (delim_index != std::string::npos) { std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ","); args.insert(args.end(), params.begin(), params.end()); } args[0] = mts::Text::toUpper(args[0]); // print help if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) { printHelp(); command.clear(); } else if (args[0].find("ATE0") == 0 && args[0].length() == 4) { _dot->setEcho(false); write(done); echo = _dot->getEcho(); } else if (args[0].find("ATE1") == 0 && args[0].length() == 4) { _dot->setEcho(true); write(done); echo = _dot->getEcho(); } else if (args[0].find("ATV0") == 0 && args[0].length() == 4) { _dot->setVerbose(false); write(done); } else if (args[0].find("ATV1") == 0 && args[0].length() == 4) { _dot->setVerbose(true); write(done); } else if (args[0] == "AT+SD") { DEBUG_PRINTF("Enter Serial Mode\r\n"); _mode = mDot::SERIAL_MODE; } else { bool found = false; bool query = false; std::string lookfor = args[0]; // per command help if ((args[0].find("?") == 0 || args[0].find("HELP") == 0)) lookfor = mts::Text::toUpper(args[1]); // trim off any trailing '?' and mark as a query command if (args[0].rfind("?") == args[0].length() - 1) { query = true; lookfor = args[0].substr(0, args[0].length() - 1); } // search for command for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) { Command* cmd = *it; // match CMD or CMD? syntax if command is queryable if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) { found = true; if (args[0] == "HELP") { writef("%s%s", cmd->help(), newline); write(done); } else if (args.size() > 1 && args[1] == "?") { writef("%s%s", cmd->usage().c_str(), newline); write(done); } else if (!cmd->verify(args)) { writef("%s%s", cmd->errorMessage().c_str(), newline); writef("%s", error); } else { if (cmd->action(args) == 0) { writef("%s", done); } else { writef("%s%s", cmd->errorMessage().c_str(), newline); writef("%s", error); } } } } if (!found) { writef("%s", command_error); writef("%s", error); } } command.clear(); } } std::string CommandTerminal::formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format) { if (format == mDot::HEXADECIMAL) return mts::Text::bin2hexString(data); else return std::string(data.begin(), data.end()); } void CommandTerminal::sleep(bool standby) { _serial_up = false; _xbee_on_sleep = GPIO_PIN_RESET; HAL_PWREx_EnableMainRegulatorLowVoltage(); HAL_PWREx_EnableFlashPowerDown(); HAL_PWREx_EnableLowRegulatorLowVoltage(); DEBUG_PRINTF("Sleep\r\n"); _dot->sleep(); if (standby) { DEBUG_PRINTF("RECORD UPLINK: %lu\r\n", _dot->getUpLinkCounter()); RTC_WriteBackupRegister(RTC_BKP_DR0, _dot->getUpLinkCounter()); HAL_PWR_EnableBkUpAccess(); HAL_EnableDBGStandbyMode(); HAL_PWR_DisableWakeUpPin (PWR_WAKEUP_PIN1); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // InterruptIn wakeon_serial(XBEE_DIN); // Application is reloaded after wake-up from standby HAL_PWR_EnterSTANDBYMode (); } else { pin_function(PA_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PA_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PA_3, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_6, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_7, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PA_8, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PA_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PA_10, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_11, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_12, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PA_15, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PB_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PB_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PB_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PC_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PC_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PC_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PC_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); // pin_function(PC_13, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); pin_function(PD_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0)); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); } wakeup_clear(); EXTI->PR = (1 << 22); // After wake-up from STOP reconfigure the PLL SetSysClock(); } bool CommandTerminal::waitForEscape(int timeout, mDot* dot, WaitType wait) { Timer timer; Timer escape_timer; std::string escape_buffer; int escape_timeout = 1000; timer.start(); while (timer.read_ms() < timeout) { if (dot != NULL) { if (wait == WAIT_SEND && (!dot->getIsTransmitting())) { return false; } } if (_serialp != NULL && _serialp->readable()) { if (escape_buffer == "") escape_timer.start(); char ch; _serialp->read(&ch, 1); escape_buffer += ch; if (escape_buffer == CommandTerminal::escape_sequence) return true; } if (escape_timer.read_ms() > escape_timeout) { escape_buffer = ""; escape_timer.stop(), escape_timer.reset(); } osDelay(10); } return false; } void CommandTerminal::wakeup(bool standby) { HAL_PWREx_DisableMainRegulatorLowVoltage(); HAL_PWREx_DisableFlashPowerDown(); HAL_PWREx_DisableLowRegulatorLowVoltage(); if (standby) { HAL_DisableDBGStandbyMode(); HAL_PWR_EnableWakeUpPin (PWR_WAKEUP_PIN1); } _dot->wakeup(); }