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
ModeSweep.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 "ModeSweep.h" 00020 #include "MTSLog.h" 00021 00022 ModeSweep::ModeSweep(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 _complete(lcd) 00031 {} 00032 00033 ModeSweep::~ModeSweep() {} 00034 00035 bool ModeSweep::start() { 00036 bool data_file = false; 00037 bool send_link_check = false; 00038 bool send_data = false; 00039 bool no_channel_link_check = false; 00040 bool no_channel_data = false; 00041 00042 // clear any stale signals 00043 osSignalClear(_main_id, buttonSignal | loraSignal); 00044 00045 _initial_data_rate = _dot->getTxDataRate(); 00046 _initial_power = _dot->getTxPower(); 00047 00048 // see if we're supposed to send the data packet after success 00049 // that item is stored in the mDot::StartUpMode config field 00050 _send_data = _dot->getStartUpMode(); 00051 00052 // pull the minimum and maximum payload size out of config 00053 // min payload size is wake interval 00054 // max payload size is wake delay 00055 _min_payload = _dot->getWakeInterval(); 00056 _max_payload = _dot->getWakeDelay(); 00057 00058 // pull the minimum and maximum power out of config 00059 // min power is wake timeout 00060 // max power is wake mode 00061 _min_power = _dot->getWakeTimeout(); 00062 _max_power = _dot->getWakeMode(); 00063 00064 // compute the total number of surveys we will do 00065 _points = generatePoints(); 00066 _survey_total = _points.size(); 00067 _survey_current = 1; 00068 _survey_success = 0; 00069 _survey_failure = 0; 00070 00071 // see if survey data file exists 00072 std::vector<mDot::mdot_file> files = _dot->listUserFiles(); 00073 for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) { 00074 if (strcmp(it->name, file_name) == 0) { 00075 logInfo("found survey data file"); 00076 data_file = true; 00077 break; 00078 } 00079 } 00080 if (data_file) { 00081 _state = check_file; 00082 _file.display(); 00083 } else { 00084 _state = show_help; 00085 _index = 1; 00086 displayHelp(); 00087 } 00088 00089 _display_timer.reset(); 00090 00091 while (true) { 00092 osEvent e = Thread::signal_wait(0, 250); 00093 if (e.status == osEventSignal) { 00094 if (e.value.signals & buttonSignal) { 00095 _be = _buttons->getButtonEvent(); 00096 00097 switch (_be) { 00098 case ButtonHandler::sw1_press: 00099 switch (_state) { 00100 case check_file: 00101 _state = show_help; 00102 _index = getIndex(sweep) + 1; 00103 displayHelp(); 00104 break; 00105 case confirm: 00106 _state = check_file; 00107 _file.display(); 00108 break; 00109 case success: 00110 _state = complete; 00111 _display_timer.stop(); 00112 _display_timer.reset(); 00113 logInfo("sweep finished"); 00114 _complete.display(); 00115 _complete.updateId(_index++); 00116 _complete.updatePass(_survey_success); 00117 _complete.updateFail(_survey_failure); 00118 _survey_success = 0; 00119 _survey_failure = 0; 00120 break; 00121 case failure: 00122 _state = complete; 00123 _display_timer.stop(); 00124 _display_timer.reset(); 00125 logInfo("sweep finished"); 00126 _complete.display(); 00127 _complete.updateId(_index++); 00128 _complete.updatePass(_survey_success); 00129 _complete.updateFail(_survey_failure); 00130 _survey_success = 0; 00131 _survey_failure = 0; 00132 break; 00133 } 00134 break; 00135 00136 case ButtonHandler::sw2_press: 00137 switch (_state) { 00138 case check_file: 00139 _state = confirm; 00140 _confirm.display(); 00141 break; 00142 case confirm: 00143 _state = show_help; 00144 logInfo("deleting survey data file"); 00145 _dot->deleteUserFile(file_name); 00146 _index = 1; 00147 displayHelp(); 00148 break; 00149 case show_help: 00150 _state = in_progress; 00151 _progress.display(); 00152 _progress.updateProgress(_survey_current, _survey_total); 00153 if (_dot->getNextTxMs() > 0) 00154 no_channel_link_check = true; 00155 else 00156 send_link_check = true; 00157 break; 00158 case complete: 00159 _state = in_progress; 00160 _survey_current = 1; 00161 _progress.display(); 00162 _progress.updateProgress(_survey_current, _survey_total); 00163 if (_dot->getNextTxMs() > 0) 00164 no_channel_link_check = true; 00165 else 00166 send_link_check = true; 00167 break; 00168 } 00169 break; 00170 case ButtonHandler::sw1_hold: 00171 _dot->setTxDataRate(_initial_data_rate); 00172 _dot->setTxPower(_initial_power); 00173 return true; 00174 } 00175 } 00176 if (e.value.signals & loraSignal) { 00177 _ls = _lora->getStatus(); 00178 switch (_ls) { 00179 case LoRaHandler::link_check_success: 00180 switch (_state) { 00181 case in_progress: 00182 _survey_success++; 00183 _link_check_result = _lora->getLinkCheckResults(); 00184 displaySuccess(); 00185 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); 00186 updateData(_data, sweep, true); 00187 appendDataFile(_data); 00188 if (_send_data) { 00189 _state = data; 00190 if (_dot->getNextTxMs() > 0) 00191 no_channel_data = true; 00192 else 00193 send_data = true; 00194 } else { 00195 _state = success; 00196 _success.updateSw1(" Cancel"); 00197 _display_timer.start(); 00198 } 00199 break; 00200 } 00201 break; 00202 00203 case LoRaHandler::link_check_failure: 00204 switch (_state) { 00205 case in_progress: 00206 _survey_failure++; 00207 _state = failure; 00208 _failure.display(); 00209 _failure.updateId(_index); 00210 _failure.updateRate(_dot->DataRateStr(_data_rate).substr(2)); 00211 _failure.updatePower(_power); 00212 if (_gps_available && _gps->getLockStatus()) { 00213 GPSPARSER::latitude lat = _gps->getLatitude(); 00214 GPSPARSER::longitude lon = _gps->getLongitude(); 00215 _failure.updateGpsLatitude(lat); 00216 _failure.updateGpsLongitude(lon); 00217 } else { 00218 _failure.updateGpsLatitude("No GPS Lock"); 00219 } 00220 _failure.updatePassFail(_survey_success, _survey_failure); 00221 _failure.updateSw1(" Cancel"); 00222 updateData(_data, sweep, false); 00223 appendDataFile(_data); 00224 logInfo("link check failed"); 00225 _display_timer.start(); 00226 break; 00227 } 00228 break; 00229 00230 case LoRaHandler::send_success: 00231 switch (_state) { 00232 case data: 00233 _state = success; 00234 _success.updateInfo(" "); 00235 _success.updateSw1(" Cancel"); 00236 logInfo("data send success"); 00237 // turn acks and receive windows back on 00238 _dot->setAck(1); 00239 _dot->setTxWait(true); 00240 _display_timer.start(); 00241 break; 00242 } 00243 break; 00244 00245 case LoRaHandler::send_failure: 00246 switch (_state) { 00247 case data: 00248 _state = success; 00249 _success.updateInfo(" "); 00250 _success.updateSw1(" Cancel"); 00251 logInfo("data send failed"); 00252 // turn acks and receive windows back on 00253 _dot->setAck(1); 00254 _dot->setTxWait(true); 00255 _display_timer.start(); 00256 break; 00257 } 00258 break; 00259 } 00260 } 00261 } 00262 00263 // wait 5s in EU mode to compensate for potential "no free channel" situations on server 00264 if ( _display_timer.read_ms() > 5000) { 00265 _display_timer.stop(); 00266 _display_timer.reset(); 00267 if (_survey_current == _survey_total) { 00268 logInfo("sweep finished"); 00269 _state = complete; 00270 _complete.display(); 00271 _complete.updateId(_index++); 00272 _complete.updatePass(_survey_success); 00273 _complete.updateFail(_survey_failure); 00274 _survey_success = 0; 00275 _survey_failure = 0; 00276 } else { 00277 logInfo("starting next link check"); 00278 _state = in_progress; 00279 _survey_current++; 00280 _progress.display(); 00281 _progress.updateProgress(_survey_current, _survey_total); 00282 no_channel_link_check = true; 00283 } 00284 } 00285 00286 if (no_channel_link_check) { 00287 uint32_t t = _dot->getNextTxMs(); 00288 if (t > 0) { 00289 logInfo("next tx %lu ms", t); 00290 _progress.updateCountdown(t / 1000); 00291 } else { 00292 _progress.display(); 00293 _progress.updateProgress(_survey_current, _survey_total); 00294 no_channel_link_check = false; 00295 send_link_check = true; 00296 } 00297 } 00298 if (no_channel_data) { 00299 uint32_t t = _dot->getNextTxMs(); 00300 if (t > 0) { 00301 logInfo("next tx %lu ms", t); 00302 _success.updateCountdown(t / 1000); 00303 } else { 00304 displaySuccess(); 00305 no_channel_data = false; 00306 send_data = true; 00307 } 00308 } 00309 if (send_link_check) { 00310 point p = _points[_survey_current - 1]; 00311 _data_rate = p.first; 00312 _power = p.second; 00313 logInfo("sending link check %s %d", _dot->DataRateStr(_data_rate).c_str(), _power); 00314 send_link_check = false; 00315 _dot->setTxDataRate(_data_rate); 00316 _dot->setTxPower(_power); 00317 _lora->linkCheck(); 00318 } 00319 if (send_data) { 00320 std::vector<uint8_t> s_data = formatSurveyData(_data); 00321 logInfo("sending data %s %d", _dot->DataRateStr(_data_rate).c_str(), _power); 00322 send_data = false; 00323 _success.updateInfo("Data Sending..."); 00324 _dot->setTxDataRate(_data_rate); 00325 _dot->setTxPower(_power); 00326 // we don't care if the server actually gets this packet or not 00327 // we won't retry anyway 00328 _dot->setAck(0); 00329 _dot->setTxWait(false); 00330 _lora->send(s_data); 00331 osDelay(500); 00332 } 00333 } 00334 } 00335 00336 void ModeSweep::displayHelp() { 00337 _help.display(); 00338 _help.updateMode("Survey Sweep"); 00339 _help.updateSw2("Sweep"); 00340 } 00341 00342 void ModeSweep::displaySuccess() { 00343 _success.display(); 00344 _success.updateId(_index); 00345 _success.updateRate(_dot->DataRateStr(_data_rate).substr(2)); 00346 _success.updatePower(_power); 00347 _success.updateStats(_link_check_result); 00348 if (_gps_available && _gps->getLockStatus()) { 00349 GPSPARSER::latitude lat = _gps->getLatitude(); 00350 GPSPARSER::longitude lon = _gps->getLongitude(); 00351 _success.updateGpsLatitude(lat); 00352 _success.updateGpsLongitude(lon); 00353 } else { 00354 _success.updateGpsLatitude("No GPS Lock"); 00355 } 00356 _success.updatePassFail(_survey_success, _survey_failure); 00357 } 00358 00359 std::vector<point> ModeSweep::generatePoints() { 00360 std::vector<point> p; 00361 uint8_t min_rate; 00362 uint8_t max_rate; 00363 00364 max_rate = payloadToRate(_min_payload); 00365 min_rate = payloadToRate(_max_payload); 00366 00367 for (int rate = min_rate; rate >= max_rate; rate--) { 00368 if (_max_power - _min_power < 4) { 00369 for (uint32_t power = _min_power; power <= _max_power; power++) 00370 p.push_back(std::make_pair(rate, power)); 00371 } else { 00372 p.push_back(std::make_pair(rate, _min_power)); 00373 p.push_back(std::make_pair(rate, (uint32_t)ceil( (float(_max_power) - float(_min_power)) * 0.33 + float(_min_power)))); 00374 p.push_back(std::make_pair(rate, (uint32_t)ceil( (float(_max_power) - float(_min_power)) * 0.66 + float(_min_power)))); 00375 p.push_back(std::make_pair(rate, _max_power)); 00376 } 00377 } 00378 00379 return p; 00380 } 00381 00382 uint8_t ModeSweep::payloadToRate(uint8_t payload) { 00383 00384 if (payload <= _dot->getMaxPacketLength()) 00385 return mDot::DR0; 00386 else 00387 return mDot::DR6; 00388 00389 } 00390
Generated on Tue Jul 12 2022 13:07:49 by 1.7.2