few changes for RTS/CTS control

Dependencies:   MTS-Serial libmDot mbed-rtos mbed

Fork of mDot_AT_firmware by MultiTech

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CommandTerminal.cpp Source File

CommandTerminal.cpp

00001 #include "ctype.h"
00002 #include "CommandTerminal.h"
00003 #include "Command.h"
00004 #include "MTSLog.h"
00005 #include <cstdarg>
00006 #include <deque>
00007 
00008 const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa XBee Module\r\n\n";
00009 const char CommandTerminal::helpline[] = "Enter '?' for help\r\n";
00010 
00011 const char CommandTerminal::newline[] = "\r\n";
00012 
00013 // Command error text...
00014 const char CommandTerminal::command_error[] = "Command not found!\r\n";
00015 
00016 // Response texts...
00017 const char CommandTerminal::help[] = "\r\nHelp\r\n";
00018 const char CommandTerminal::cmd_error[] = "Invalid command\r\n";
00019 const char CommandTerminal::connect[] = "\r\nCONNECT\r\n";
00020 const char CommandTerminal::no_carrier[] = "\r\nNO CARRIER\r\n";
00021 const char CommandTerminal::done[] = "\r\nOK\r\n";
00022 const char CommandTerminal::error[] = "\r\nERROR\r\n";
00023 
00024 // Escape sequence...
00025 const char CommandTerminal::escape_sequence[] = "+++";
00026 
00027 mts::ATSerial* CommandTerminal::_serialp = NULL;
00028 
00029 static bool serial_data_mode = false;
00030 static bool peer_to_peer = false;
00031 
00032 void CommandTerminal::addCommand(Command* cmd) {
00033     _commands.push_back(cmd);
00034 }
00035 
00036 CommandTerminal::CommandTerminal(mts::ATSerial& serial, mDot* dot)
00037 :
00038   _serial(serial),
00039   _dot(dot),
00040   _events(new RadioEvent(serial)),
00041   _mode(mDot::COMMAND_MODE),
00042   _idle_thread(idle, NULL, osPriorityLow),
00043   _sleep_standby(true),
00044   _xbee_on_sleep(XBEE_ON_SLEEP) {
00045 
00046     _dot->setEvents(_events);
00047     _dot->setWakeupCallback(this, &CommandTerminal::wakeup);
00048     _serialp = &serial;
00049 
00050     addCommand(new CmdAttention(_dot));
00051     addCommand(new CmdIdentification(_dot, serial));
00052     addCommand(new CmdResetCpu(_dot, serial));
00053     addCommand(new CmdDummy(_dot, "Enable/Disable Echo", "ATE", "ATE0: disable, ATE1: enable"));
00054     addCommand(new CmdDummy(_dot, "Enable/Disable Verbose", "ATV", "ATV0: disable, ATV1: enable"));
00055     addCommand(new CmdDummy(_dot, "Hardware Flow Control", "AT&K", "AT&K0: disable, AT&K3: enable"));
00056 
00057     addCommand(new CmdFactoryDefault(_dot));
00058     addCommand(new CmdSaveConfig(_dot));
00059     addCommand(new CmdDisplayConfig(_dot, serial));
00060     addCommand(new CmdDisplayStats(_dot, serial));
00061     addCommand(new CmdResetStats(_dot, serial));
00062     addCommand(new CmdSerialBaudRate(_dot, serial));
00063     addCommand(new CmdDebugBaudRate(_dot, serial));
00064     addCommand(new CmdStartUpMode(_dot, serial));
00065 
00066     addCommand(new CmdFrequencyBand(_dot, serial));
00067     addCommand(new CmdFrequencySubBand(_dot, serial));
00068     addCommand(new CmdPublicNetwork(_dot, serial));
00069     addCommand(new CmdDeviceId(_dot, serial));
00070     addCommand(new CmdDeviceClass(_dot, serial));
00071 
00072     addCommand(new CmdAppPort(_dot, serial));
00073     addCommand(new CmdNetworkAddress(_dot, serial));
00074     addCommand(new CmdNetworkSessionKey(_dot, serial));
00075     addCommand(new CmdDataSessionKey(_dot, serial));
00076     addCommand(new CmdUplinkCounter(_dot, serial));
00077     addCommand(new CmdDownlinkCounter(_dot, serial));
00078     addCommand(new CmdSaveSession(_dot, serial));
00079     addCommand(new CmdRestoreSession(_dot, serial));
00080     addCommand(new CmdNetworkKey(_dot, serial));
00081     addCommand(new CmdNetworkId(_dot, serial));
00082 
00083     addCommand(new CmdJoinDelay(_dot, serial));
00084     addCommand(new CmdJoinRequest(_dot, serial));
00085     addCommand(new CmdJoinRetries(_dot, serial));
00086     addCommand(new CmdJoinByteOrder(_dot, serial));
00087     addCommand(new CmdNetworkJoinMode(_dot, serial));
00088     addCommand(new CmdPreserveSession(_dot, serial));
00089     addCommand(new CmdNetworkJoinStatus(_dot, serial));
00090     addCommand(new CmdNetworkLinkCheck(_dot, serial));
00091     addCommand(new CmdLinkCheckCount(_dot, serial));
00092     addCommand(new CmdLinkCheckThreshold(_dot, serial));
00093     addCommand(new CmdEncryption(_dot, serial));
00094 
00095     addCommand(new CmdRssi(_dot, serial));
00096     addCommand(new CmdSnr(_dot, serial));
00097     addCommand(new CmdDataPending(_dot, serial));
00098 
00099     addCommand(new CmdSessionDataRate(_dot, serial));
00100 
00101     addCommand(new CmdTxDataRate(_dot, serial));
00102     addCommand(new CmdTxPower(_dot, serial));
00103     addCommand(new CmdAntennaGain(_dot, serial));
00104     addCommand(new CmdTxFrequency(_dot, serial));
00105     addCommand(new CmdTxInverted(_dot, serial));
00106     addCommand(new CmdTxWait(_dot, serial));
00107     addCommand(new CmdTxChannel(_dot, serial));
00108     addCommand(new CmdTxNextMs(_dot, serial));
00109     addCommand(new CmdTimeOnAir(_dot, serial));
00110 
00111     addCommand(new CmdRxDelay(_dot, serial));
00112     addCommand(new CmdRxOutput(_dot, serial));
00113     addCommand(new CmdRxInverted(_dot, serial));
00114 
00115     addCommand(new CmdErrorCorrection(_dot, serial));
00116     addCommand(new CmdCRC(_dot, serial));
00117     addCommand(new CmdAdaptiveDataRate(_dot, serial));
00118 
00119     addCommand(new CmdACKAttempts(_dot, serial));
00120     addCommand(new CmdRepeat(_dot, serial));
00121 
00122     addCommand(new CmdSendString(_dot, serial));
00123     addCommand(new CmdSendBinary(_dot, serial));
00124     addCommand(new CmdReceiveOnce(_dot, serial));
00125 
00126     addCommand(new CmdDummy(_dot, "Serial Data Mode", "AT+SD", "Enter serial data mode, exit with '+++'"));
00127     addCommand(new CmdDummy(_dot, "Sleep Mode", "AT+SLEEP", "Enter sleep mode (0:deepsleep,1:sleep)"));
00128     addCommand(new CmdSerialClearOnError(_dot, serial));
00129     addCommand(new CmdWakeMode(_dot, serial));
00130     addCommand(new CmdWakeInterval(_dot, serial));
00131     addCommand(new CmdWakePin(_dot, serial));
00132     addCommand(new CmdWakeDelay(_dot, serial));
00133     addCommand(new CmdWakeTimeout(_dot, serial));
00134     addCommand(new CmdPing(_dot, serial));
00135     addCommand(new CmdLogLevel(_dot, serial));
00136 
00137     addCommand(new CmdDummy(_dot, "***** Test Commands *****", "", ""));
00138     addCommand(new CmdRxDataRate(_dot, serial));
00139     addCommand(new CmdRxFrequency(_dot, serial));
00140     addCommand(new CmdReceiveContinuous(_dot, serial));
00141     addCommand(new CmdSendStringOnInterval(_dot, serial));
00142 }
00143 
00144 void CommandTerminal::printHelp() {
00145     const char* name = NULL;
00146     const char* text = NULL;
00147     const char* desc = NULL;
00148     const char* tab = "\t";
00149 
00150     std::string header("Command");
00151     header.append(tab);
00152     header.append(tab);
00153     header.append("Name");
00154     header.append(tab);
00155     header.append(tab);
00156     header.append(tab);
00157     header.append("Description");
00158 
00159     write(newline);
00160     write(header.c_str());
00161     write(newline);
00162     write(newline);
00163     for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
00164         name = (*it)->name();
00165         text = (*it)->text();
00166         desc = (*it)->desc();
00167         write(text);
00168         if (strlen(text) < 8)
00169             write(tab);
00170         write(tab);
00171         write(name);
00172         if (strlen(name) < 8)
00173             write(tab);
00174         if (strlen(name) < 16)
00175             write(tab);
00176         write(tab);
00177         write(desc);
00178         write(newline);
00179     }
00180 
00181     write(newline);
00182 }
00183 
00184 bool CommandTerminal::writeable() {
00185     return _serial.writeable();
00186 }
00187 
00188 bool CommandTerminal::readable() {
00189     return _serial.readable();
00190 }
00191 
00192 char CommandTerminal::read() {
00193     char ch;
00194     _serial.read(&ch, 1);
00195     return ch;
00196 }
00197 
00198 void CommandTerminal::write(const char* message) {
00199     while (!writeable())
00200         ;
00201     _serial.write(message, strlen(message));
00202 }
00203 
00204 void CommandTerminal::writef(const char* format, ...) {
00205     char buff[256];
00206 
00207     va_list ap;
00208     va_start(ap, format);
00209     int size = vsnprintf(buff, 256, format, ap);
00210     while (!writeable())
00211         ;
00212     _serial.write(buff, size);
00213     va_end(ap);
00214 }
00215 
00216 void CommandTerminal::serialLoop() {
00217     Timer serial_read_timer;
00218     std::vector<uint8_t> serial_buffer;
00219     std::vector<uint8_t> data;
00220     int timeout = 0;
00221 
00222     serial_read_timer.start();
00223 
00224     if (_dot->getStartUpMode() == mDot::SERIAL_MODE) {
00225         _xbee_on_sleep = GPIO_PIN_SET;
00226 
00227         timeout = _dot->getWakeDelay();
00228 
00229         // wait for timeout or start of serial data
00230         while (!readable() && serial_read_timer.read_ms() < timeout && !_serial.escaped()) {
00231             osDelay(2);
00232         }
00233     }
00234 
00235     if (readable() && !_serial.escaped()) {
00236 
00237         serial_read_timer.reset();
00238         timeout = _dot->getWakeTimeout();
00239 
00240         while (serial_read_timer.read_ms() < timeout && serial_buffer.size() <= _dot->getMaxPacketLength()) {
00241             while (readable() && serial_buffer.size() < _dot->getMaxPacketLength()) {
00242                 serial_buffer.push_back(read());
00243                 serial_read_timer.reset();
00244 
00245                 if (_serial.escaped())
00246                     break;
00247             }
00248         }
00249 
00250         serial_read_timer.stop(), serial_read_timer.reset();
00251 
00252         if (!serial_buffer.empty()) {
00253             if (_dot->getStartUpMode() == mDot::SERIAL_MODE)
00254                 _xbee_on_sleep = GPIO_PIN_RESET;
00255 
00256             // wait for any duty cycle limit to expire
00257             while (_dot->getNextTxMs() > 0 && !_serial.escaped()) {
00258                 osDelay(10);
00259             }
00260 
00261             if (!_dot->getIsTransmitting()) {
00262                 logDebug("Received serial data, sending out radio.");
00263 
00264                 if (_dot->send(serial_buffer, false) != mDot::MDOT_OK) {
00265                     logDebug("Send failed.");
00266                     // If the data should be tossed after send failure, clear buffer
00267                     if (_dot->getSerialClearOnError()) {
00268                         serial_buffer.clear();
00269                     }
00270                 } else {
00271 
00272                     // wait for send to finish
00273                     while (_dot->getIsTransmitting() && !_serial.escaped())
00274                         osDelay(10);
00275 
00276                     // call recv to wait for any packet before sending again
00277                     if (!_serial.escaped())
00278                         _dot->recv(data);
00279 
00280                     // Clear the serial buffer if send is success
00281                     serial_buffer.clear();
00282                 }
00283             } else {
00284                 logDebug("Radio is busy, cannot send.\r\n");
00285                 osDelay(10);
00286             }
00287 
00288         } else {
00289             logDebug("No data received from serial to send.\r\n");
00290         }
00291     }
00292 
00293     if (!_serial.readable() && _dot->getStartUpMode() == mDot::SERIAL_MODE && !_serial.escaped()) {
00294         _xbee_on_sleep = GPIO_PIN_RESET;
00295         sleep(_sleep_standby);
00296     }
00297 
00298     if (_serial.escaped()) {
00299         _serial.clearEscaped();
00300         _serial.rxClear();
00301         serial_data_mode = false;
00302         _mode = mDot::COMMAND_MODE;
00303         logDebug("Exit Serial Mode");
00304         write(done);
00305         return;
00306     }
00307 
00308     if (!_dot->getNetworkJoinStatus()) {
00309         serial_data_mode = false;
00310         _mode = mDot::COMMAND_MODE;
00311         logDebug("Exit Serial Mode");
00312         write(no_carrier);
00313         return;
00314     }
00315 }
00316 
00317 bool CommandTerminal::autoJoinCheck() {
00318 
00319     std::string escape_buffer;
00320     int sleep = 1000;
00321     Timer tmr;
00322     tmr.start();
00323     int cnt = 0;
00324 
00325     while (!_dot->getNetworkJoinStatus()) {
00326         write("\r\nJoining network... ");
00327 
00328         if (_dot->getNextTxMs() > 0) {
00329             int rand_time = rand() % 10000;
00330             writef("\r\nWaiting %lu s before next join attempt\r\n", (_dot->getNextTxMs() + rand_time) / 1000);
00331 
00332             tmr.reset();
00333             while (_dot->getNextTxMs() > 0 && !_serial.escaped()) {
00334                 osDelay(2);
00335             }
00336 
00337             tmr.reset();
00338             while (tmr.read_ms() < rand_time && !_serial.escaped())
00339                 osDelay(10);
00340         }
00341 
00342         if (!_serial.escaped() && _dot->joinNetworkOnce() == mDot::MDOT_OK) {
00343             write("Network Joined\r\n");
00344             write(done);
00345             return false;
00346         }
00347 
00348         write("Network Join failed\r\n");
00349         write(error);
00350 
00351         if (!_serial.escaped() && _dot->getJoinRetries() > 0 && cnt++ > _dot->getJoinRetries()) {
00352             cnt = 0;
00353 
00354             if (_dot->getFrequencyBand() == mDot::FB_915) {
00355                 uint8_t band = ((_dot->getFrequencySubBand()) % 8) + 1;
00356                 logWarning("Join retries exhausted, switching to sub band %u", band);
00357                 _dot->setFrequencySubBand(band);
00358             }
00359 
00360             if (sleep < 60 * 60 * 1000)
00361                 sleep *= 2;
00362         }
00363 
00364         tmr.reset();
00365         while (tmr.read_ms() < sleep && !_serial.escaped()) {
00366             osDelay(10);
00367         }
00368 
00369         if (_serial.escaped()) {
00370             _serial.clearEscaped();
00371             serial_data_mode = false;
00372             _mode = mDot::COMMAND_MODE;
00373             write("Join Canceled\r\n");
00374             write(done);
00375             return true;
00376         }
00377     }
00378 
00379     return false;
00380 }
00381 
00382 void CommandTerminal::start() {
00383 
00384     char ch;
00385     bool running = true;
00386     bool echo = _dot->getEcho();
00387     std::string command;
00388     std::deque<std::string> history;
00389     int history_index = -1;
00390     std::vector<std::string> args;
00391     bool join_canceled = false;
00392 
00393     if (_dot->getStartUpMode() == mDot::SERIAL_MODE) {
00394 
00395         serial_data_mode = true;
00396         _mode = mDot::SERIAL_MODE;
00397 
00398         std::string escape_buffer;
00399         char ch;
00400 
00401         if (!_dot->getStandbyFlag()) {
00402             // wake up from power-on/reset
00403 
00404             int escape_timeout = 1000;
00405             Timer tmr;
00406             Timer escape_tmr;
00407 
00408             // wait one second for possible escape by user pressing '+' key
00409             tmr.reset();
00410             tmr.start();
00411             escape_tmr.reset();
00412             escape_tmr.start();
00413             while (tmr.read_ms() < escape_timeout) {
00414                 if (_serial.readable()) {
00415                     _serial.read(&ch, 1);
00416                     escape_buffer += ch;
00417                 }
00418 
00419                 if (escape_buffer.find("+") != std::string::npos) {
00420                     logInfo("Escape detected");
00421                     join_canceled = true;
00422                     serial_data_mode = false;
00423                     _mode = mDot::COMMAND_MODE;
00424                     command.clear();
00425                     break;
00426                 }
00427 
00428                 if (escape_tmr.read_ms() > escape_timeout)
00429                     escape_buffer.clear();
00430 
00431                 osDelay(1);
00432             }
00433         }
00434 
00435         if (_mode == mDot::SERIAL_MODE && !_dot->getNetworkJoinStatus() && _dot->getJoinMode() == mDot::OTA) {
00436             if (_dot->joinNetworkOnce() != mDot::MDOT_OK) {
00437                 serial_data_mode = false;
00438                 _mode = mDot::COMMAND_MODE;
00439 
00440                 logWarning("Start Up Mode set to SERIAL_MODE, but join failed.");
00441                 _serial.writef("Network Not Joined\r\n");
00442                 _serial.writef(error);
00443             }
00444         }
00445     }
00446 
00447     if (_dot->getJoinMode() == mDot::PEER_TO_PEER) {
00448         peer_to_peer = true;
00449     } else {
00450         peer_to_peer = false;
00451     }
00452 
00453 
00454 
00455     //Run terminal session
00456     while (running) {
00457 
00458         // wait for input to reduce at command idle current
00459         while (!readable() || _mode == mDot::SERIAL_MODE) {
00460             if (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA) {
00461                 join_canceled = autoJoinCheck();
00462                 if (join_canceled)
00463                     command.clear();
00464             }
00465 
00466             if (_dot->getJoinMode() != mDot::AUTO_OTA || (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA)) {
00467                 switch (_mode) {
00468                     case mDot::SERIAL_MODE:
00469                         // signal wakeup, read serial and output to radio
00470                         serialLoop();
00471                         continue;
00472                         break;
00473                     default:
00474                         break;
00475                 }
00476             }
00477 
00478             ch = '\0';
00479 
00480             wait(0.00001); // 10 us
00481             _serial.escaped();
00482         }
00483 
00484         // read characters
00485         if (readable()) {
00486             ch = read();
00487 
00488             if (ch == '\b' || ch == 0x7f) {
00489                 if (!command.empty()) {
00490                     writef("\b \b");
00491                     command.erase(command.size() - 1);
00492                 }
00493                 continue;
00494             } else if (ch == 0x1b || ch == 0x09) {
00495                 osDelay(20);
00496                 // catch escape sequence, or tab
00497                 char ch1 = 0x00, ch2 = 0x00;
00498 
00499                 if (readable()) {
00500                     ch1 = read();
00501                     if (readable())
00502                         ch2 = read();
00503 
00504                     if (ch1 == 0x5b && ch2 == 0x41) {
00505                         // up key
00506                         for (size_t i = 0; i < command.size() + 1; i++) {
00507                             writef("\b \b");
00508                         }
00509                         if (history.size() > 0) {
00510                             if (++history_index >= int(history.size() - 1))
00511                                 history_index = history.size() - 1;
00512 
00513                             command = history[history_index];
00514                             writef("%s", history[history_index].c_str());
00515                         } else {
00516                             command.clear();
00517                         }
00518                     } else if (ch1 == 0x5b && ch2 == 0x42) {
00519 
00520                         // down key
00521                         for (size_t i = 0; i < command.size() + 1; i++) {
00522                             writef("\b \b");
00523                         }
00524 
00525                         if (--history_index < 0) {
00526                             history_index = -1;
00527                             command.clear();
00528                         } else {
00529                             command = history[history_index];
00530                             writef("%s", history[history_index].c_str());
00531                         }
00532                     }
00533                 }
00534                 while (readable())
00535                     read();
00536                 continue;
00537             } else {
00538                 command += ch;
00539             }
00540 
00541             // echo chars if enabled
00542             if (echo && !(ch == '\r' || ch == '\n'))
00543                 writef("%c", ch);
00544         }
00545 
00546         // look for end of command line
00547         if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
00548             // remove new line or cr character
00549             command.erase(command.size() - 1);
00550             write("\r"); // match standard modem output
00551             write(newline);
00552         } else {
00553             continue;
00554         }
00555 
00556         // trim whitespace from command
00557         mts::Text::trim(command, "\r\n\t ");
00558 
00559         if (command.size() < 1) {
00560             command.clear();
00561             continue;
00562         }
00563 
00564         // parse command and args
00565         args.clear();
00566 
00567         // find first '=' character
00568         size_t delim_index = command.find("=");
00569         if (delim_index != std::string::npos) {
00570             args.push_back(command.substr(0, delim_index));
00571         } else {
00572             // find first ' ' character
00573             delim_index = command.find(" ");
00574             if (delim_index != std::string::npos) {
00575                 args.push_back(command.substr(0, delim_index));
00576             } else {
00577                 args.push_back(command);
00578             }
00579         }
00580 
00581         if (delim_index != std::string::npos) {
00582             std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
00583             args.insert(args.end(), params.begin(), params.end());
00584         }
00585 
00586         args[0] = mts::Text::toUpper(args[0]);
00587 
00588         // print help
00589         if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
00590             printHelp();
00591             command.clear();
00592         } else if ((args[0].find("ATE?") == 0 && args[0].length() == 4) || (args[0].find("ATE") == 0 && args[0].length() == 3)) {
00593             writef("%d\r\n", _dot->getEcho());
00594             write(done);
00595         } else if (args[0].find("ATE0") == 0 && args[0].length() == 4) {
00596             _dot->setEcho(false);
00597             write(done);
00598             echo = _dot->getEcho();
00599         } else if (args[0].find("ATE1") == 0 && args[0].length() == 4) {
00600             _dot->setEcho(true);
00601             write(done);
00602             echo = _dot->getEcho();
00603         } else if ((args[0].find("ATV?") == 0 && args[0].length() == 4) || (args[0].find("ATV") == 0 && args[0].length() == 3)) {
00604             writef("%d\r\n", _dot->getVerbose());
00605             write(done);
00606         } else if (args[0].find("ATV0") == 0 && args[0].length() == 4) {
00607             _dot->setVerbose(false);
00608             write(done);
00609         } else if (args[0].find("ATV1") == 0 && args[0].length() == 4) {
00610             _dot->setVerbose(true);
00611             write(done);
00612         } else if ((args[0].find("AT&K?") == 0 && args[0].length() == 5) || (args[0].find("AT&K") == 0 && args[0].length() == 4)) {
00613             writef("%d\r\n", (_dot->getFlowControl() ? 3 : 0));
00614             write(done);
00615         } else if (args[0].find("AT&K0") == 0 && args[0].length() == 5) {
00616             _dot->setFlowControl(false);
00617             write(done);
00618         } else if (args[0].find("AT&K3") == 0 && args[0].length() == 5) {
00619             _dot->setFlowControl(true);
00620             write(done);
00621         } else if (args[0] == "AT+SD") {
00622             if (_dot->getNetworkJoinStatus()) {
00623                 logDebug("Enter Serial Mode");
00624                 write(connect);
00625                 serial_data_mode = true;
00626                 _mode = mDot::SERIAL_MODE;
00627             } else {
00628                 logDebug("Network Not Joined");
00629                 write("Network Not Joined\r\n");
00630                 write(error);
00631             }
00632         } else if (args[0] == "AT+SLEEP") {
00633             if (args.size() > 2 && (args[1] != "?")) {
00634                 write("Invalid argument\r\n");
00635                 write(error);
00636             } else {
00637                 if (args.size() > 1 && args[1] == "?") {
00638                     write("(0:deepsleep,1:sleep)\r\n");
00639                     write(done);
00640                 } else {
00641                     _sleep_standby = !(args.size() > 1 && args[1] == "1");
00642                     write(done);
00643                     this->sleep(_sleep_standby);
00644                     wait(0.1);
00645                 }
00646             }
00647         } else {
00648             bool found = false;
00649             bool query = false;
00650 
00651             std::string lookfor = args[0];
00652 
00653             // per command help
00654             if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
00655                 lookfor = mts::Text::toUpper(args[1]);
00656 
00657             // trim off any trailing '?' and mark as a query command
00658             if (args[0].rfind("?") == args[0].length() - 1) {
00659                 query = true;
00660                 lookfor = args[0].substr(0, args[0].length() - 1);
00661             }
00662 
00663             // search for command
00664             for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
00665                 Command* cmd = *it;
00666 
00667                 // match CMD or CMD? syntax if command is queryable
00668                 if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
00669                     found = true;
00670                     if (args[0] == "HELP") {
00671                         writef("%s%s", cmd->help(), newline);
00672                         write(done);
00673                     }
00674 
00675                     else if (args.size() > 1 && args[1] == "?") {
00676                         writef("%s%s", cmd->usage().c_str(), newline);
00677                         write(done);
00678                     } else if (!cmd->verify(args)) {
00679                         writef("%s%s", cmd->errorMessage().c_str(), newline);
00680                         writef("%s", error);
00681                     } else {
00682                         if (cmd->action(args) == 0) {
00683                             writef("%s", done);
00684                         } else {
00685                             writef("%s%s", cmd->errorMessage().c_str(), newline);
00686                             writef("%s", error);
00687                         }
00688                     }
00689                 }
00690             }
00691 
00692             if (!found) {
00693                 writef("%s", command_error);
00694                 writef("%s", error);
00695             }
00696         }
00697 
00698         if (history.size() == 0 || history.front() != command)
00699             history.push_front(command);
00700         history_index = -1;
00701         command.clear();
00702 
00703         while (history.size() > 10)
00704             history.pop_back();
00705     }
00706 }
00707 
00708 std::string CommandTerminal::formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format) {
00709     if (format == mDot::HEXADECIMAL)
00710         return mts::Text::bin2hexString(data);
00711     else
00712         return std::string(data.begin(), data.end());
00713 }
00714 
00715 void CommandTerminal::sleep(bool standby) {
00716     _xbee_on_sleep = GPIO_PIN_RESET;
00717 
00718     _serial.rxClear();
00719     _serial.txClear();
00720 
00721     _dot->sleep(_dot->getWakeInterval(), _dot->getWakeMode(), standby);
00722 }
00723 
00724 bool CommandTerminal::waitForEscape(int timeout, mDot* dot, WaitType wait) {
00725     Timer timer;
00726 
00727     timer.start();
00728     while (timer.read_ms() < timeout) {
00729 
00730         if (dot != NULL) {
00731             if (wait == WAIT_SEND && (!dot->getIsTransmitting())) {
00732                 return false;
00733             }
00734         }
00735 
00736         if (_serialp != NULL && _serialp->escaped()) {
00737             _serialp->clearEscaped();
00738             return true;
00739         }
00740 
00741         osDelay(10);
00742     }
00743 
00744     return false;
00745 }
00746 
00747 void CommandTerminal::wakeup(void) {
00748     if (_dot->getWakePin() == XBEE_DIN) {
00749         _serial.reattach(XBEE_DOUT, XBEE_DIN);
00750         logInfo("Wakeup pin was serial input");
00751     }
00752 }
00753 
00754 void CommandTerminal::RadioEvent::MacEvent(LoRaMacEventFlags* flags, LoRaMacEventInfo* info) {
00755 
00756     if (mts::MTSLog::getLogLevel() == mts::MTSLog::TRACE_LEVEL) {
00757         std::string msg = "OK";
00758         switch (info->Status) {
00759             case LORAMAC_EVENT_INFO_STATUS_ERROR:
00760                 msg = "ERROR";
00761                 break;
00762             case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT:
00763                 msg = "TX_TIMEOUT";
00764                 break;
00765             case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT:
00766                 msg = "RX_TIMEOUT";
00767                 break;
00768             case LORAMAC_EVENT_INFO_STATUS_RX_ERROR:
00769                 msg = "RX_ERROR";
00770                 break;
00771             case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL:
00772                 msg = "JOIN_FAIL";
00773                 break;
00774             case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_FAIL:
00775                 msg = "DOWNLINK_FAIL";
00776                 break;
00777             case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL:
00778                 msg = "ADDRESS_FAIL";
00779                 break;
00780             case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL:
00781                 msg = "MIC_FAIL";
00782                 break;
00783             default:
00784                 break;
00785         }
00786         logTrace("Event: %s", msg.c_str());
00787 
00788         logTrace("Flags Tx: %d Rx: %d RxData: %d RxSlot: %d LinkCheck: %d JoinAccept: %d",
00789                  flags->Bits.Tx, flags->Bits.Rx, flags->Bits.RxData, flags->Bits.RxSlot, flags->Bits.LinkCheck, flags->Bits.JoinAccept);
00790         logTrace("Info: Status: %d ACK: %d Retries: %d TxDR: %d RxPort: %d RxSize: %d RSSI: %d SNR: %d Energy: %d Margin: %d Gateways: %d",
00791                  info->Status, info->TxAckReceived, info->TxNbRetries, info->TxDatarate, info->RxPort, info->RxBufferSize,
00792                  info->RxRssi, info->RxSnr, info->Energy, info->DemodMargin, info->NbGateways);
00793     }
00794 
00795     if (flags->Bits.Rx) {
00796         if (serial_data_mode) {
00797             logDebug("Rx %d bytes", info->RxBufferSize);
00798             if (info->RxBufferSize > 0) {
00799                 _serial.write((char*) info->RxBuffer, info->RxBufferSize);
00800             }
00801         }
00802 
00803         delete[] info->RxBuffer;
00804     }
00805 }
00806 
00807 CommandTerminal::~CommandTerminal() {
00808     delete _events;
00809 }