Factory firmware for the MultiTech Dotbox (MTDOT-BOX) and EVB (MTDOT-EVB) products.

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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ModeSingle.cpp Source File

ModeSingle.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 "ModeSingle.h"
00020 #include "MTSLog.h"
00021 
00022 ModeSingle::ModeSingle(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
00023   : Mode(lcd, buttons, dot, lora, gps, sensors),
00024     _help(lcd),
00025     _file(lcd),
00026     _confirm(lcd),
00027     _progress(lcd),
00028     _success(lcd),
00029     _failure(lcd)
00030 {}
00031 
00032 ModeSingle::~ModeSingle() {}
00033 
00034 bool ModeSingle::start() {
00035     bool data_file = false;
00036     bool send_link_check = false;
00037     bool send_data = false;
00038     bool no_channel_link_check = false;
00039     bool no_channel_data = false;
00040 
00041     // clear any stale signals
00042     osSignalClear(_main_id, buttonSignal | loraSignal);
00043 
00044     _initial_data_rate = _dot->getTxDataRate() < _dot->getMinDatarate() ? _dot->getMinDatarate() : _dot->getTxDataRate();
00045     _initial_power = _dot->getTxPower();
00046     _data_rate = _dot->getMinDatarate();
00047 
00048 
00049     // see if we're supposed to send the data packet after success
00050     // that item is stored in the mDot::StartUpMode config field
00051     _send_data = _dot->getStartUpMode();
00052 
00053     // see if survey data file exists
00054     std::vector<mDot::mdot_file> files = _dot->listUserFiles();
00055     for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) {
00056         if (strcmp(it->name, file_name) == 0) {
00057             logInfo("found survey data file");
00058             data_file = true;
00059             break;
00060         }
00061     }
00062     if (data_file) {
00063         _state = check_file;
00064         _file.display();
00065     } else {
00066         _state = show_help;
00067         _index = 0;
00068         displayHelp();
00069     }
00070 
00071     while (true) {
00072         osEvent e = Thread::signal_wait(0, 250);
00073         if (e.status == osEventSignal) {
00074             if (e.value.signals & buttonSignal) {
00075                 _be = _buttons->getButtonEvent();
00076 
00077                 switch (_be) {
00078                     case ButtonHandler::sw1_press:
00079                         switch (_state) {
00080                             case check_file:
00081                                 _state = show_help;
00082                                 _index = getIndex(single);
00083                                 displayHelp();
00084                                 break;
00085                             case confirm:
00086                                 _state = check_file;
00087                                 _file.display();
00088                                 break;
00089                             case show_help:
00090                                 incrementRatePower();
00091                                 _help.updateMsg(formatRatePower());
00092                                 break;
00093                             case success:
00094                                 incrementRatePower();
00095                                 _success.updateInfo(formatRatePower());
00096                                 break;
00097                             case failure:
00098                                 incrementRatePower();
00099                                 _failure.updateInfo(formatRatePower());
00100                                 break;
00101                         }
00102                         break;
00103 
00104                     case ButtonHandler::sw2_press:
00105                         switch (_state) {
00106                             case check_file:
00107                                 _state = confirm;
00108                                 _confirm.display();
00109                                 break;
00110                             case confirm:
00111                                 _state = show_help;
00112                                 logInfo("deleting survey data file");
00113                                 _dot->deleteUserFile(file_name);
00114                                 _index = 0;
00115                                 displayHelp();
00116                                 break;
00117                             case show_help:
00118                                 _state = in_progress;
00119                                 _progress.display();
00120                                 if (_dot->getNextTxMs() > 0)
00121                                     no_channel_link_check = true;
00122                                 else 
00123                                     send_link_check = true;
00124                                 break;
00125                             case success:
00126                                 _state = in_progress;
00127                                 _progress.display();
00128                                 if (_dot->getNextTxMs() > 0)
00129                                     no_channel_link_check = true;
00130                                 else 
00131                                     send_link_check = true;
00132                                 break;
00133                             case failure:
00134                                 _state = in_progress;
00135                                 _progress.display();
00136                                 if (_dot->getNextTxMs() > 0)
00137                                     no_channel_link_check = true;
00138                                 else 
00139                                     send_link_check = true;
00140                                 break;
00141                         }
00142                         break;
00143                     case ButtonHandler::sw1_hold:
00144                         _dot->setTxDataRate(_initial_data_rate);
00145                         _dot->setTxPower(_initial_power);
00146                         return true;
00147                 }
00148             }
00149             if (e.value.signals & loraSignal) {
00150                 _ls = _lora->getStatus();
00151                 switch (_ls) {
00152                     case LoRaHandler::link_check_success:
00153                         switch (_state) {
00154                             case in_progress:
00155                                 _link_check_result = _lora->getLinkCheckResults();
00156                                 displaySuccess();
00157                                 logInfo("link check successful\tMargin %ld\tRSSI %d dBm\tSNR %2.3f", _link_check_result.up.dBm, _link_check_result.down.rssi, (float)_link_check_result.down.snr / 10.0);
00158                                 updateData(_data, single, true);
00159                                 appendDataFile(_data);
00160                                 if (_send_data) {
00161                                     _state = data;
00162                                     if (_dot->getNextTxMs() > 0)
00163                                         no_channel_data = true;
00164                                     else
00165                                         send_data = true;
00166                                 } else {
00167                                     _state = success;
00168                                     _success.updateSw1("  DR/PWR");
00169                                     _success.updateSw2("Survey");
00170                                 }
00171                                 break;
00172                         }
00173                         break;
00174 
00175                     case LoRaHandler::link_check_failure:
00176                         switch (_state) {
00177                             case in_progress:
00178                                 _state = failure;
00179                                 _failure.display();
00180                                 _failure.updateId(_index);
00181                                 // mDot::DataRateStr returns format DRXX - we only want to display the XX part
00182                                 _failure.updateRate(_dot->DataRateStr(_data_rate).substr(2));
00183                                 updateData(_data, single, false);
00184                                 appendDataFile(_data);
00185                                 _failure.updatePower(_power);
00186                                 if (_gps_available && _gps->getLockStatus()) {
00187                                     GPSPARSER::latitude lat = _gps->getLatitude();
00188                                     GPSPARSER::longitude lon = _gps->getLongitude();
00189                                     struct tm time = _gps->getTimestamp();
00190                                     _failure.updateGpsLatitude(lat);
00191                                     _failure.updateGpsLongitude(lon);
00192                                     _failure.updateGpsTime(time);
00193                                 } else {
00194                                     _failure.updateGpsLatitude("No GPS Lock");
00195                                 }
00196                                 _failure.updateSw1("  DR/PWR");
00197                                 _failure.updateSw2("Survey");
00198                                 logInfo("link check failed");
00199                                 break;
00200                         }
00201                         break;
00202 
00203                     case LoRaHandler::send_success:
00204                         switch (_state) {
00205                             case data:
00206                                 _state = success;
00207                                 _success.updateInfo("                 ");
00208                                 _success.updateSw1("  DR/PWR");
00209                                 _success.updateSw2("Survey");
00210                                 // turn acks and receive windows back on
00211                                 _dot->setAck(1);
00212                                 _dot->setTxWait(true);
00213                                 logInfo("data send success");
00214                                 break;
00215                         }
00216                         break;
00217 
00218                     case LoRaHandler::send_failure:
00219                         switch (_state) {
00220                             case data:
00221                                 _state = success;
00222                                 _success.updateInfo("                 ");
00223                                 _success.updateSw1("  DR/PWR");
00224                                 _success.updateSw2("Survey");
00225                                 // turn acks and receive windows back on
00226                                 _dot->setAck(1);
00227                                 _dot->setTxWait(true);
00228                                 logInfo("data send failed");
00229                                 break;
00230                         }
00231                         break;
00232                 }
00233             }
00234         }
00235 
00236         if (no_channel_link_check) {
00237             uint32_t t = _dot->getNextTxMs();
00238             if (t > 0) {
00239                 logInfo("next tx %lu ms", t);
00240                 _progress.updateCountdown(t / 1000);
00241             } else {
00242                 _progress.display();
00243                 no_channel_link_check = false;
00244                 send_link_check = true;
00245             }
00246         }
00247         if (no_channel_data) {
00248             uint32_t t = _dot->getNextTxMs();
00249             if (t > 0) {
00250                 logInfo("next tx %lu ms", t);
00251                 _success.updateCountdown(t / 1000);
00252             } else {
00253                 displaySuccess();
00254                 no_channel_data = false;
00255                 send_data = true;
00256             }
00257         }
00258         if (send_link_check) {
00259             logInfo("sending link check %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
00260             send_link_check = false;
00261             _dot->setTxDataRate(_data_rate);
00262             _dot->setTxPower(_power);
00263             _lora->linkCheck();
00264             _index++;
00265         }
00266         if (send_data) {
00267             std::vector<uint8_t> s_data = formatSurveyData(_data);
00268             logInfo("sending data %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
00269             send_data = false;
00270             _success.updateInfo("Data Sending...");
00271             _dot->setTxDataRate(_data_rate);
00272             _dot->setTxPower(_power);
00273             // we don't care if the server actually gets this packet or not
00274             // we won't retry anyway
00275             _dot->setAck(0);
00276             _dot->setTxWait(false);
00277             _lora->send(s_data);
00278             osDelay(500);
00279         }
00280     }
00281 }
00282 
00283 void ModeSingle::displayHelp() {
00284     _help.display();
00285     _help.updateMode("Survey Single");
00286     _help.updateSw1("  DR/PWR");
00287     _help.updateSw2("Survey");
00288     _help.updateMsg(formatRatePower());
00289 }
00290 
00291 void ModeSingle::displaySuccess() {
00292     uint8_t fix = _gps->getFixStatus();
00293     _success.display();
00294     _success.updateId(_index);
00295     // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
00296     _success.updateRate(_dot->DataRateStr(_data_rate).substr(2));
00297     _success.updatePower(_power);
00298     _success.updateStats(_link_check_result);
00299     if (_gps_available && _gps->getLockStatus()) {
00300         GPSPARSER::latitude lat = _gps->getLatitude();
00301         GPSPARSER::longitude lon = _gps->getLongitude();
00302         struct tm time = _gps->getTimestamp();
00303         _success.updateGpsLatitude(lat);
00304         _success.updateGpsLongitude(lon);
00305         _success.updateGpsTime(time);
00306     } else {
00307         _success.updateGpsLatitude("No GPS Lock");
00308     }
00309 }
00310 
00311 std::string ModeSingle::formatRatePower() {
00312     std::string msg;
00313     char buf[8];
00314     size_t size;
00315 
00316     msg += "DR=";
00317     msg += _dot->DataRateStr(_data_rate).substr(2);
00318     msg += " P=";
00319     size = snprintf(buf, sizeof(buf), "%u", _power);
00320     msg.append(buf, size);
00321 
00322     return msg;
00323 }
00324 
00325 void ModeSingle::incrementRatePower() {
00326     if (_power <= 2) {
00327         _power = 20;
00328         _data_rate++;        
00329         if (_data_rate > _dot->getMaxDatarate()) {
00330             _data_rate = _dot->getMinDatarate();       
00331         }
00332     } else {
00333         _power -= 3;
00334     }
00335 
00336     logInfo("new data rate %s, power %lu", mDot::DataRateStr(_data_rate).c_str(), _power);
00337 }
00338