MultiTech / Mbed OS MTDOT-BOX-EVB-Factory-Firmware

Dependencies:   NCP5623B GpsParser ISL29011 libmDot-mbed5 MTS-Serial MMA845x DOGS102 MPL3115A2

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ModeConfig.cpp Source File

ModeConfig.cpp

00001 /* Copyright (c) <2016> <MultiTech Systems>, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or 
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "ModeConfig.h"
00020 #include "ctype.h"
00021 #include "Command.h"
00022 #include "ButtonHandler.h"
00023 #include <cstdarg>
00024 #include <deque>
00025 
00026 const char ModeConfig::newline[] = "\r\n";
00027 
00028 // Command error text...
00029 const char ModeConfig::command_error[] = "Command not found!\r\n";
00030 
00031 // Response texts...
00032 const char ModeConfig::done[] = "\r\nOK\r\n";
00033 const char ModeConfig::error[] = "\r\nERROR\r\n";
00034 
00035 void ModeConfig::addCommand(Command* cmd) {
00036     _commands.push_back(cmd);
00037 }
00038 
00039 ModeConfig::ModeConfig(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
00040 : Mode(lcd, buttons, dot, lora, gps, sensors),
00041   _lc(lcd),
00042   _serial(USBTX, USBRX, 512, 512)
00043 {
00044     _serial.baud(115200);
00045 
00046     addCommand(new CmdAttention(_dot));
00047     addCommand(new CmdIdentification(_dot, _serial));
00048     addCommand(new CmdFactoryDefault(_dot));
00049     addCommand(new CmdSaveConfig(_dot));
00050     addCommand(new CmdDisplayConfig(_dot, _serial));
00051 
00052     addCommand(new CmdFrequencyBand(_dot, _serial));
00053     addCommand(new CmdFrequencySubBand(_dot, _serial));
00054     addCommand(new CmdPublicNetwork(_dot, _serial));
00055     addCommand(new CmdJoinDelay(_dot, _serial));
00056     addCommand(new CmdDeviceId(_dot, _serial));
00057 
00058     addCommand(new CmdNetworkAddress(_dot, _serial));
00059     addCommand(new CmdNetworkSessionKey(_dot, _serial));
00060     addCommand(new CmdDataSessionKey(_dot, _serial));
00061     addCommand(new CmdNetworkKey(_dot, _serial));
00062     addCommand(new CmdNetworkId(_dot, _serial));
00063 
00064     addCommand(new CmdNetworkJoinMode(_dot, _serial));
00065     addCommand(new CmdTxDataRate(_dot, _serial));
00066     addCommand(new CmdTxPower(_dot, _serial));
00067 
00068     addCommand(new CmdMinimumSize(_dot, _serial));
00069     addCommand(new CmdMaximumSize(_dot, _serial));
00070     addCommand(new CmdMinimumPower(_dot, _serial));
00071     addCommand(new CmdMaximumPower(_dot, _serial));
00072     addCommand(new CmdData(_dot, _serial));
00073     addCommand(new CmdGetSurveyDataFile(_dot, _serial));
00074     addCommand(new CmdDeleteSurveyDataFile(_dot, _serial));
00075     addCommand(new CmdDummy(_dot, "Exit to main menu", "AT+EXIT", "Exit configuration and return to the main menu"));
00076 
00077 #if MTS_RADIO_DEBUG_COMMANDS
00078     addCommand(new CmdWriteProtectedConfig(_dot));
00079     addCommand(new CmdSendContinuous(_dot));
00080     addCommand(new CmdTxFrequency(_dot));
00081 #endif
00082 }
00083 
00084 void ModeConfig::printHelp() {
00085     const char* name = NULL;
00086     const char* text = NULL;
00087     const char* desc = NULL;
00088     const char* tab = "\t";
00089 
00090     std::string header("Command");
00091     header.append(tab);
00092     header.append(tab);
00093     header.append("Name");
00094     header.append(tab);
00095     header.append(tab);
00096     header.append(tab);
00097     header.append("Description");
00098 
00099     write(newline);
00100     write(header.c_str());
00101     write(newline);
00102     write(newline);
00103     for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
00104         name = (*it)->name();
00105         text = (*it)->text();
00106         desc = (*it)->desc();
00107         write(text);
00108         if (strlen(text) < 8)
00109             write(tab);
00110         write(tab);
00111         write(name);
00112         if (strlen(name) < 8)
00113             write(tab);
00114         if (strlen(name) < 16)
00115             write(tab);
00116         write(tab);
00117         write(desc);
00118         write(newline);
00119     }
00120 
00121     write(newline);
00122 }
00123 
00124 bool ModeConfig::writeable() {
00125     return _serial.writeable();
00126 }
00127 
00128 bool ModeConfig::readable() {
00129     return _serial.readable();
00130 }
00131 
00132 char ModeConfig::read() {
00133     char ch;
00134     _serial.read(&ch, 1);
00135     return ch;
00136 }
00137 
00138 void ModeConfig::write(const char* message) {
00139     while (!writeable())
00140         ;
00141     _serial.write(message, strlen(message));
00142 }
00143 
00144 void ModeConfig::writef(const char* format, ...) {
00145     char buff[256];
00146 
00147     va_list ap;
00148     va_start(ap, format);
00149     int size = vsnprintf(buff, 256, format, ap);
00150     while (!writeable())
00151         ;
00152     _serial.write(buff, size);
00153     va_end(ap);
00154 }
00155 
00156 bool ModeConfig::start() {
00157     char ch;
00158     bool running = true;
00159     bool echo = _dot->getEcho();
00160     std::string command;
00161     std::deque<std::string> history;
00162     int history_index = -1;
00163     std::vector<std::string> args;
00164 
00165     osSignalClear(_main_id, buttonSignal);
00166 
00167     _lc.display();
00168 
00169     //Run terminal session
00170     while (running) {
00171         _lc.roll();
00172            
00173         osEvent e = Thread::signal_wait(buttonSignal, 20);
00174         if (e.status == osEventSignal) {
00175             ButtonHandler::ButtonEvent _be = _buttons->getButtonEvent();
00176             switch (_be) {
00177                 case ButtonHandler::sw1_press:
00178                     _band = _dot->getFrequencyBand();
00179                     break;
00180                 case ButtonHandler::sw2_press:
00181                     _band = _dot->getFrequencyBand();
00182                     break;
00183                 case ButtonHandler::sw1_hold:
00184                     _band = _dot->getFrequencyBand();
00185                     return true;
00186                 default:
00187                     break;
00188             }
00189         }
00190         
00191         ch = '\0';
00192 
00193         // read characters
00194         if (readable()) {
00195             ch = read();
00196 
00197             if (ch == '\b' || ch == 0x7f) {
00198                 if (!command.empty()) {
00199                     writef("\b \b");
00200                     command.erase(command.size() - 1);
00201                 }
00202                 continue;
00203             } else if (ch == 0x1b || ch == 0x09) {
00204                 osDelay(20);
00205                 // catch escape sequence, or tab
00206                 char ch1, ch2;
00207 
00208                 if (readable()) {
00209                     ch1 = read();
00210                     if (readable())
00211                         ch2 = read();
00212 
00213                     if (ch1 == 0x5b && ch2 == 0x41) {
00214                         // up key
00215                         for (int i = 0; i < command.size()+1; i++) {
00216                             writef("\b \b");
00217                         }
00218                         if (history.size() > 0) {
00219                             if (++history_index >= history.size() - 1)
00220                                 history_index = history.size() - 1;
00221 
00222                             command = history[history_index];
00223                             writef("%s", history[history_index].c_str());
00224                         } else {
00225                             command.clear();
00226                         }
00227                     } else if (ch1 == 0x5b && ch2 == 0x42) {
00228 
00229                         // down key
00230                         for (int i = 0; i < command.size()+1; i++) {
00231                             writef("\b \b");
00232                         }
00233 
00234                         if (--history_index < 0) {
00235                             history_index = -1;
00236                             command.clear();
00237                         } else {
00238                             command = history[history_index];
00239                             writef("%s", history[history_index].c_str());
00240                         }
00241                     }
00242                 }
00243                 while (readable()) read();
00244                 continue;
00245             } else {
00246                 command += ch;
00247             }
00248 
00249             // echo chars if enabled
00250             if (echo && !(ch == '\r' || ch == '\n'))
00251                 writef("%c", ch);
00252         }
00253 
00254         // look for end of command line
00255         if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
00256             // remove new line or cr character
00257             command.erase(command.size() - 1);
00258             write("\r"); // match standard modem output
00259             write(newline);
00260         } else {
00261             continue;
00262         }
00263 
00264         // trim whitespace from command
00265         mts::Text::trim(command, "\r\n\t ");
00266 
00267         if (command.size() < 1) {
00268             command.clear();
00269             continue;
00270         }
00271 
00272         // parse command and args
00273         args.clear();
00274 
00275         // find first '=' character
00276         size_t delim_index = command.find("=");
00277         if (delim_index != std::string::npos) {
00278             args.push_back(command.substr(0, delim_index));
00279         } else {
00280             // find first ' ' character
00281             delim_index = command.find(" ");
00282             if (delim_index != std::string::npos) {
00283                 args.push_back(command.substr(0, delim_index));
00284             } else {
00285                 args.push_back(command);
00286             }
00287         }
00288 
00289         if (delim_index != std::string::npos) {
00290             std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
00291             args.insert(args.end(), params.begin(), params.end());
00292         }
00293 
00294         args[0] = mts::Text::toUpper(args[0]);
00295 
00296         // print help
00297         if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
00298             printHelp();
00299             command.clear();
00300         } else if (args[0].find("AT+EXIT") == 0 && args[0].length() == 7) {
00301             write(done); 
00302             _band = _dot->getFrequencyBand();       
00303         return true;
00304         } else {
00305             bool found = false;
00306             bool query = false;
00307 
00308             std::string lookfor = args[0];
00309 
00310             // per command help
00311             if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
00312                 lookfor = mts::Text::toUpper(args[1]);
00313 
00314             // trim off any trailing '?' and mark as a query command
00315             if (args[0].rfind("?") == args[0].length() - 1) {
00316                 query = true;
00317                 lookfor = args[0].substr(0, args[0].length() - 1);
00318             }
00319 
00320             // search for command
00321             for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
00322                 Command* cmd = *it;
00323 
00324                 // match CMD or CMD? syntax if command is queryable
00325                 if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
00326                     found = true;
00327                     if (args[0] == "HELP") {
00328                         writef("%s%s", cmd->help(), newline);
00329                         write(done);
00330                     }
00331 
00332                     else if (args.size() > 1 && args[1] == "?") {
00333                         writef("%s%s", cmd->usage().c_str(), newline);
00334                         write(done);
00335                     } else if (!cmd->verify(args)) {
00336                         writef("%s%s", cmd->errorMessage().c_str(), newline);
00337                         writef("%s", error);
00338                     } else {
00339                         if (cmd->action(args) == 0) {
00340                             writef("%s", done);
00341                         } else {
00342                             writef("%s%s", cmd->errorMessage().c_str(), newline);
00343                             writef("%s", error);
00344                         }
00345                     }
00346                 }
00347             }
00348 
00349             if (!found) {
00350                 writef("%s", command_error);
00351                 writef("%s", error);
00352             }
00353         }
00354 
00355         if (history.size() == 0 || history.front() != command)
00356             history.push_front(command);
00357         history_index = -1;
00358         command.clear();
00359 
00360         while (history.size() > 10)
00361             history.pop_back();
00362 
00363     }
00364         _band = _dot->getFrequencyBand();
00365     return false;
00366 }