Custom Channel Plan version of MTDOT Box firmware

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

Fork of MTDOT-BOX-EVB-Factory-Firmware by MultiTech

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 CmdDeviceId(_dot, _serial));
00056 
00057     addCommand(new CmdNetworkAddress(_dot, _serial));
00058     addCommand(new CmdNetworkSessionKey(_dot, _serial));
00059     addCommand(new CmdDataSessionKey(_dot, _serial));
00060     addCommand(new CmdNetworkKey(_dot, _serial));
00061     addCommand(new CmdNetworkId(_dot, _serial));
00062 
00063     addCommand(new CmdNetworkJoinMode(_dot, _serial));
00064     addCommand(new CmdTxDataRate(_dot, _serial));
00065     addCommand(new CmdTxPower(_dot, _serial));
00066 
00067     addCommand(new CmdMinimumSize(_dot, _serial));
00068     addCommand(new CmdMaximumSize(_dot, _serial));
00069     addCommand(new CmdMinimumPower(_dot, _serial));
00070     addCommand(new CmdMaximumPower(_dot, _serial));
00071     addCommand(new CmdData(_dot, _serial));
00072     addCommand(new CmdGetSurveyDataFile(_dot, _serial));
00073     addCommand(new CmdDeleteSurveyDataFile(_dot, _serial));
00074     addCommand(new CmdDummy(_dot, "Exit to main menu", "AT+EXIT", "Exit configuration and return to the main menu"));
00075 
00076 #if MTS_RADIO_DEBUG_COMMANDS
00077     addCommand(new CmdWriteProtectedConfig(_dot));
00078     addCommand(new CmdSendContinuous(_dot));
00079     addCommand(new CmdTxFrequency(_dot));
00080 #endif
00081 }
00082 
00083 void ModeConfig::printHelp() {
00084     const char* name = NULL;
00085     const char* text = NULL;
00086     const char* desc = NULL;
00087     const char* tab = "\t";
00088 
00089     std::string header("Command");
00090     header.append(tab);
00091     header.append(tab);
00092     header.append("Name");
00093     header.append(tab);
00094     header.append(tab);
00095     header.append(tab);
00096     header.append("Description");
00097 
00098     write(newline);
00099     write(header.c_str());
00100     write(newline);
00101     write(newline);
00102     for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
00103         name = (*it)->name();
00104         text = (*it)->text();
00105         desc = (*it)->desc();
00106         write(text);
00107         if (strlen(text) < 8)
00108             write(tab);
00109         write(tab);
00110         write(name);
00111         if (strlen(name) < 8)
00112             write(tab);
00113         if (strlen(name) < 16)
00114             write(tab);
00115         write(tab);
00116         write(desc);
00117         write(newline);
00118     }
00119 
00120     write(newline);
00121 }
00122 
00123 bool ModeConfig::writeable() {
00124     return _serial.writeable();
00125 }
00126 
00127 bool ModeConfig::readable() {
00128     return _serial.readable();
00129 }
00130 
00131 char ModeConfig::read() {
00132     char ch;
00133     _serial.read(&ch, 1);
00134     return ch;
00135 }
00136 
00137 void ModeConfig::write(const char* message) {
00138     while (!writeable())
00139         ;
00140     _serial.write(message, strlen(message));
00141 }
00142 
00143 void ModeConfig::writef(const char* format, ...) {
00144     char buff[256];
00145 
00146     va_list ap;
00147     va_start(ap, format);
00148     int size = vsnprintf(buff, 256, format, ap);
00149     while (!writeable())
00150         ;
00151     _serial.write(buff, size);
00152     va_end(ap);
00153 }
00154 
00155 bool ModeConfig::start() {
00156     char ch;
00157     bool running = true;
00158     bool echo = _dot->getEcho();
00159     std::string command;
00160     std::deque<std::string> history;
00161     int history_index = -1;
00162     std::vector<std::string> args;
00163 
00164     osSignalClear(_main_id, buttonSignal);
00165 
00166     _lc.display();
00167 
00168     //Run terminal session
00169     while (running) {
00170         _lc.roll();
00171            
00172         osEvent e = Thread::signal_wait(buttonSignal, 20);
00173         if (e.status == osEventSignal) {
00174             ButtonHandler::ButtonEvent _be = _buttons->getButtonEvent();
00175             switch (_be) {
00176                 case ButtonHandler::sw1_press:
00177                     break;
00178                 case ButtonHandler::sw2_press:
00179                     break;
00180                 case ButtonHandler::sw1_hold:
00181                     return true;
00182                 default:
00183                     break;
00184             }
00185         }
00186         
00187         ch = '\0';
00188 
00189         // read characters
00190         if (readable()) {
00191             ch = read();
00192 
00193             if (ch == '\b' || ch == 0x7f) {
00194                 if (!command.empty()) {
00195                     writef("\b \b");
00196                     command.erase(command.size() - 1);
00197                 }
00198                 continue;
00199             } else if (ch == 0x1b || ch == 0x09) {
00200                 osDelay(20);
00201                 // catch escape sequence, or tab
00202                 char ch1, ch2;
00203 
00204                 if (readable()) {
00205                     ch1 = read();
00206                     if (readable())
00207                         ch2 = read();
00208 
00209                     if (ch1 == 0x5b && ch2 == 0x41) {
00210                         // up key
00211                         for (int i = 0; i < command.size()+1; i++) {
00212                             writef("\b \b");
00213                         }
00214                         if (history.size() > 0) {
00215                             if (++history_index >= history.size() - 1)
00216                                 history_index = history.size() - 1;
00217 
00218                             command = history[history_index];
00219                             writef("%s", history[history_index].c_str());
00220                         } else {
00221                             command.clear();
00222                         }
00223                     } else if (ch1 == 0x5b && ch2 == 0x42) {
00224 
00225                         // down key
00226                         for (int i = 0; i < command.size()+1; i++) {
00227                             writef("\b \b");
00228                         }
00229 
00230                         if (--history_index < 0) {
00231                             history_index = -1;
00232                             command.clear();
00233                         } else {
00234                             command = history[history_index];
00235                             writef("%s", history[history_index].c_str());
00236                         }
00237                     }
00238                 }
00239                 while (readable()) read();
00240                 continue;
00241             } else {
00242                 command += ch;
00243             }
00244 
00245             // echo chars if enabled
00246             if (echo && !(ch == '\r' || ch == '\n'))
00247                 writef("%c", ch);
00248         }
00249 
00250         // look for end of command line
00251         if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
00252             // remove new line or cr character
00253             command.erase(command.size() - 1);
00254             write("\r"); // match standard modem output
00255             write(newline);
00256         } else {
00257             continue;
00258         }
00259 
00260         // trim whitespace from command
00261         mts::Text::trim(command, "\r\n\t ");
00262 
00263         if (command.size() < 1) {
00264             command.clear();
00265             continue;
00266         }
00267 
00268         // parse command and args
00269         args.clear();
00270 
00271         // find first '=' character
00272         size_t delim_index = command.find("=");
00273         if (delim_index != std::string::npos) {
00274             args.push_back(command.substr(0, delim_index));
00275         } else {
00276             // find first ' ' character
00277             delim_index = command.find(" ");
00278             if (delim_index != std::string::npos) {
00279                 args.push_back(command.substr(0, delim_index));
00280             } else {
00281                 args.push_back(command);
00282             }
00283         }
00284 
00285         if (delim_index != std::string::npos) {
00286             std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
00287             args.insert(args.end(), params.begin(), params.end());
00288         }
00289 
00290         args[0] = mts::Text::toUpper(args[0]);
00291 
00292         // print help
00293         if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
00294             printHelp();
00295             command.clear();
00296         } else if (args[0].find("AT+EXIT") == 0 && args[0].length() == 7) {
00297             write(done);        
00298         return true;
00299         } else {
00300             bool found = false;
00301             bool query = false;
00302 
00303             std::string lookfor = args[0];
00304 
00305             // per command help
00306             if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
00307                 lookfor = mts::Text::toUpper(args[1]);
00308 
00309             // trim off any trailing '?' and mark as a query command
00310             if (args[0].rfind("?") == args[0].length() - 1) {
00311                 query = true;
00312                 lookfor = args[0].substr(0, args[0].length() - 1);
00313             }
00314 
00315             // search for command
00316             for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
00317                 Command* cmd = *it;
00318 
00319                 // match CMD or CMD? syntax if command is queryable
00320                 if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
00321                     found = true;
00322                     if (args[0] == "HELP") {
00323                         writef("%s%s", cmd->help(), newline);
00324                         write(done);
00325                     }
00326 
00327                     else if (args.size() > 1 && args[1] == "?") {
00328                         writef("%s%s", cmd->usage().c_str(), newline);
00329                         write(done);
00330                     } else if (!cmd->verify(args)) {
00331                         writef("%s%s", cmd->errorMessage().c_str(), newline);
00332                         writef("%s", error);
00333                     } else {
00334                         if (cmd->action(args) == 0) {
00335                             writef("%s", done);
00336                         } else {
00337                             writef("%s%s", cmd->errorMessage().c_str(), newline);
00338                             writef("%s", error);
00339                         }
00340                     }
00341                 }
00342             }
00343 
00344             if (!found) {
00345                 writef("%s", command_error);
00346                 writef("%s", error);
00347             }
00348         }
00349 
00350         if (history.size() == 0 || history.front() != command)
00351             history.push_front(command);
00352         history_index = -1;
00353         command.clear();
00354 
00355         while (history.size() > 10)
00356             history.pop_back();
00357 
00358     }
00359     return false;
00360 }