Factory firmware for the MultiTech Dotbox (MTDOT-BOX) and EVB (MTDOT-EVB) products.
Dependencies: NCP5623B GpsParser ISL29011 libmDot-mbed5 MTS-Serial MMA845x DOGS102 MPL3115A2
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
Generated on Tue Jul 12 2022 17:02:18 by 1.7.2