Factory firmware for the MultiTech Dotbox (MTDOT-BOX) and EVB (MTDOT-EVB) products.
Dependencies: NCP5623B GpsParser ISL29011 libmDot-mbed5 MTS-Serial MMA845x DOGS102 MPL3115A2
Mode.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 "Mode.h" 00020 #include "MTSLog.h" 00021 00022 /* 00023 * union for converting from 32-bit to 4 8-bit values 00024 */ 00025 union convert32 { 00026 int32_t f_s; // convert from signed 32 bit int 00027 uint32_t f_u; // convert from unsigned 32 bit int 00028 uint8_t t_u[4]; // convert to 8 bit unsigned array 00029 }convertL; 00030 00031 /* 00032 * union for converting from 16- bit to 2 8-bit values 00033 */ 00034 union convert16 { 00035 int16_t f_s; // convert from signed 16 bit int 00036 uint16_t f_u; // convert from unsigned 16 bit int 00037 uint8_t t_u[2]; // convert to 8 bit unsigned array 00038 } convertS; 00039 00040 00041 Mode::Mode(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors) 00042 : _lcd(lcd), 00043 _buttons(buttons), 00044 _dot(dot), 00045 _lora(lora), 00046 _gps(gps), 00047 _sensors(sensors), 00048 _main_id(Thread::gettid()), 00049 _index(0), 00050 _band(_dot->getFrequencyBand()), 00051 _sub_band(_dot->getFrequencySubBand()), 00052 _data_rate(mDot::DR0), 00053 _power(20), 00054 _next_tx(0), 00055 _send_data(false), 00056 _gps_available(_gps->gpsDetected()) 00057 {} 00058 00059 Mode::~Mode() {} 00060 00061 bool Mode::deleteDataFile() { 00062 bool ret = true; 00063 00064 // if survey data file exists, attempt to delete it 00065 std::vector<mDot::mdot_file> files = _dot->listUserFiles(); 00066 for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) 00067 if (it->name == file_name) { 00068 if (! _dot->deleteUserFile(file_name)) 00069 ret = false; 00070 break; 00071 } 00072 00073 return ret; 00074 } 00075 00076 // ID, Status, Lock, Lat, Long, Alt, Time, RSSIup, SNRup, RSSIdown, SNRdown, DataRate, Power 00077 bool Mode::appendDataFile(const DataItem& data) { 00078 char main_buf[256]; 00079 char id_buf[16]; 00080 char lat_buf[32]; 00081 char lon_buf[32]; 00082 char alt_buf[16]; 00083 char time_buf[32]; 00084 char stats_buf[32]; 00085 size_t size; 00086 00087 snprintf(id_buf, sizeof(id_buf), "%c%ld", (data.type == single) ? 'L' : 'S', data.index); 00088 00089 // if we had GPS lock, format GPS data 00090 if (data.gps_lock) { 00091 snprintf(lat_buf, sizeof(lat_buf), "%d %d %d.%03d %c", 00092 (int) abs(data.gps_latitude.degrees), 00093 (int) data.gps_latitude.minutes, 00094 (int) (data.gps_latitude.seconds * 6) / 1000, 00095 (int) (data.gps_latitude.seconds * 6) % 1000, 00096 (data.gps_latitude.degrees > 0) ? 'N' : 'S'); 00097 snprintf(lon_buf, sizeof(lon_buf), "%d %d %d.%03d %c", 00098 (int) abs(data.gps_longitude.degrees), 00099 (int) data.gps_longitude.minutes, 00100 (int) (data.gps_longitude.seconds * 6) / 1000, 00101 (int) (data.gps_longitude.seconds * 6) % 1000, 00102 (data.gps_longitude.degrees > 0) ? 'E' : 'W'); 00103 snprintf(alt_buf, sizeof(alt_buf), "%d", 00104 data.gps_altitude); 00105 snprintf(time_buf, sizeof(time_buf), "%02d:%02d:%02d %02d/%02d/%04d", 00106 data.gps_time.tm_hour, 00107 data.gps_time.tm_min, 00108 data.gps_time.tm_sec, 00109 data.gps_time.tm_mon + 1, 00110 data.gps_time.tm_mday, 00111 data.gps_time.tm_year + 1900); 00112 } 00113 00114 if (data.status) { 00115 float down_snr = (float)data.link.down.snr / 10.0; 00116 snprintf(stats_buf, sizeof(stats_buf), "%lu,%ld,%d,%2.1f", 00117 data.link.up.gateways, 00118 data.link.up.dBm, 00119 (int)abs(data.link.down.rssi), 00120 down_snr); 00121 } 00122 00123 size = snprintf(main_buf, sizeof(main_buf), "%s,%c,%ld,%s,%s,%s,%s,%s,%s,%lu\n", 00124 id_buf, 00125 data.status ? 'S' : 'F', 00126 data.gps_lock ? data.gps_sats : 0, 00127 (data.gps_lock) ? lat_buf : "", 00128 (data.gps_lock) ? lon_buf : "", 00129 (data.gps_lock) ? alt_buf : "", 00130 (data.gps_lock) ? time_buf : "", 00131 data.status ? stats_buf : ",,,", 00132 _dot->DataRateStr(data.data_rate).substr(2).c_str(), 00133 data.power); 00134 00135 if (size < 0) { 00136 logError("failed to format survey data"); 00137 return false; 00138 } 00139 00140 if (! _dot->appendUserFile(file_name, (void*)main_buf, size)) { 00141 logError("failed to write survey data to file"); 00142 return false; 00143 } else { 00144 logInfo("successfully wrote survey data to file\r\n\t%s", main_buf); 00145 } 00146 00147 return true; 00148 } 00149 00150 void Mode::updateData(DataItem& data, DataType type, bool status) { 00151 data.type = type; 00152 data.index = _index; 00153 data.status = status; 00154 data.gps_lock = _gps->getLockStatus(); 00155 data.gps_sats = _gps->getNumSatellites(); 00156 data.gps_longitude = _gps->getLongitude(); 00157 data.gps_latitude = _gps->getLatitude(); 00158 data.gps_altitude = _gps->getAltitude(); 00159 data.gps_time = _gps->getTimestamp(); 00160 data.link = _link_check_result; 00161 data.data_rate = _data_rate; 00162 data.power = _power; 00163 } 00164 00165 void Mode::updateSensorData(SensorItem& data) { 00166 data.accel_data = _sensors->getAcceleration(); 00167 data.baro_data = _sensors->getBarometer(); 00168 data.lux_data_raw = _sensors->getLightRaw(); 00169 data.pressure_raw = _sensors->getPressureRaw(); 00170 data.light = _sensors->getLight(); 00171 data.pressure = _sensors->getPressure(); 00172 data.altitude = _sensors->getAltitude(); 00173 data.temperature = _sensors->getTemp(SensorHandler::CELSIUS); 00174 } 00175 00176 uint32_t Mode::getIndex(DataType type) { 00177 uint32_t index = 0; 00178 mDot::mdot_file file; 00179 size_t buf_size = 128; 00180 char buf[buf_size]; 00181 bool done = false; 00182 char search; 00183 00184 int read_offset; 00185 int read_size; 00186 int reduce = buf_size - 32; 00187 int bytes_read; 00188 int ret; 00189 int current; 00190 00191 if (type == single) 00192 search = 'L'; 00193 else 00194 search = 'S'; 00195 00196 file = _dot->openUserFile(file_name, mDot::FM_RDONLY); 00197 if (file.fd < 0) { 00198 logError("failed to open survey data file"); 00199 } else { 00200 //logInfo("file size %d", file.size); 00201 if (file.size > buf_size) { 00202 read_offset = file.size - buf_size - 1; 00203 read_size = buf_size; 00204 } else { 00205 read_offset = 0; 00206 read_size = file.size; 00207 } 00208 00209 while (! done) { 00210 if (read_offset == 0) 00211 done = true; 00212 00213 //logInfo("reading from index %d, %d bytes", read_offset, read_size); 00214 00215 if (! _dot->seekUserFile(file, read_offset, SEEK_SET)) { 00216 logError("failed to seek %d/%d", read_offset, file.size); 00217 return 0; 00218 } 00219 memset(buf, 0, buf_size); 00220 ret = _dot->readUserFile(file, (void*)buf, read_size); 00221 if (ret != read_size) { 00222 logError("failed to read"); 00223 return 0; 00224 } 00225 //logInfo("read %d bytes [%s]", ret, buf); 00226 bytes_read = file.size - read_offset; 00227 //logInfo("read %d total bytes", bytes_read); 00228 00229 // read_size - 1 is the last byte in the buffer 00230 for (current = read_size - 1; current >= 0; current--) { 00231 // generic case where a preceding newline exists 00232 if (buf[current] == '\n' && current != read_size - 1) { 00233 int test = current; 00234 //logInfo("found potential %d, %c", read_offset + current, buf[test + 1]); 00235 if (buf[test + 1] == search) { 00236 sscanf(&buf[test + 2], "%ld", &index); 00237 done = true; 00238 break; 00239 } 00240 // special case where the index we're looking for is in the first entry - no newline 00241 } else if (current == 0 && bytes_read >= file.size) { 00242 int test = current; 00243 //logInfo("found potential %d, %c", read_offset + current, buf[test + 1]); 00244 if (buf[test] == search) { 00245 sscanf(&buf[test + 1], "%ld", &index); 00246 done = true; 00247 break; 00248 } 00249 } 00250 } 00251 00252 read_offset = (read_offset - reduce > 0) ? read_offset - reduce : 0; 00253 } 00254 _dot->closeUserFile(file); 00255 } 00256 00257 logInfo("returning index %d", index); 00258 00259 return index; 00260 } 00261 00262 std::vector<uint8_t> Mode::formatSurveyData(DataItem& data) { 00263 std::vector<uint8_t> send_data; 00264 uint8_t satfix; 00265 00266 send_data.clear(); 00267 send_data.push_back(0x1D); // key for start of data structure 00268 send_data.push_back(0x1A); // key for uplink QOS + RF Pwr 00269 convertS.f_s = data.link.up.gateways; 00270 send_data.push_back(convertS.t_u[1]); 00271 send_data.push_back(convertS.t_u[0]); 00272 send_data.push_back((data.link.up.dBm) & 0xFF); 00273 send_data.push_back(data.power); 00274 00275 send_data.push_back(0x1B); // key for downlink QOS 00276 convertS.f_s=data.link.down.rssi; 00277 send_data.push_back(convertS.t_u[1]); 00278 send_data.push_back(convertS.t_u[0]); 00279 send_data.push_back((data.link.down.snr/10) & 0xFF); 00280 00281 // collect GPS data if GPS device detected 00282 if (_gps->gpsDetected() && ((_data_rate != lora::SF_10) || (lora::ChannelPlan::IsPlanDynamic(_band)))) { 00283 send_data.push_back(0x19); // key for GPS Lock Status 00284 satfix = (_gps->getNumSatellites() << 4 ) | (_gps->getFixStatus() & 0x0F ); 00285 send_data.push_back(satfix); 00286 00287 if (_gps->getLockStatus()){ // if gps has a lock 00288 // Send GPS data if GPS device locked 00289 send_data.push_back(0x15); // key for GPS Latitude 00290 send_data.push_back(data.gps_latitude.degrees); 00291 send_data.push_back(data.gps_latitude.minutes); 00292 convertS.f_s = data.gps_latitude.seconds; 00293 send_data.push_back(convertS.t_u[1]); 00294 send_data.push_back(convertS.t_u[0]); 00295 00296 send_data.push_back(0x16); // key for GPS Longitude 00297 convertS.f_s = data.gps_longitude.degrees; 00298 send_data.push_back(convertS.t_u[1]); 00299 send_data.push_back(convertS.t_u[0]); 00300 00301 send_data.push_back(data.gps_longitude.minutes); 00302 convertS.f_s = data.gps_longitude.seconds; 00303 send_data.push_back(convertS.t_u[1]); 00304 send_data.push_back(convertS.t_u[0]); 00305 } 00306 } 00307 // key for end of data structure 00308 send_data.push_back(0x1D); 00309 00310 return send_data; 00311 } 00312 00313 std::vector<uint8_t> Mode::formatSensorData(SensorItem& data) { 00314 std::vector<uint8_t> send_data; 00315 send_data.clear(); 00316 send_data.push_back(0x0E); // key for Current Acceleration 3-Axis Value 00317 convertS.f_s = data.accel_data._x *4; // shift data 2 bits while retaining sign 00318 send_data.push_back(convertS.t_u[1]); // get 8 MSB of 14 bit value 00319 convertS.f_s = data.accel_data._y * 4; // shift data 2 bits while retaining sign 00320 send_data.push_back(convertS.t_u[1]); // get 8 MSB of 14 bit value 00321 convertS.f_s = data.accel_data._z * 4; // shift data 2 bits while retaining sign 00322 send_data.push_back(convertS.t_u[1]); // get 8 MSB of 14 bit value 00323 send_data.push_back(0x08); // key for Current Pressure Value 00324 convertL.f_u = data.pressure_raw; // pressure data is 20 bits unsigned 00325 send_data.push_back(convertL.t_u[2]); 00326 send_data.push_back(convertL.t_u[1]); 00327 send_data.push_back(convertL.t_u[0]); 00328 send_data.push_back(0x05); // key for Current Ambient Light Value 00329 convertS.f_u = data.lux_data_raw; // data is 16 bits unsigned 00330 send_data.push_back(convertS.t_u[1]); 00331 send_data.push_back(convertS.t_u[0]); 00332 send_data.push_back(0x0B); // key for Current Temperature Value 00333 convertS.f_s = data.baro_data._temp; // temperature is signed 12 bit 00334 send_data.push_back(convertS.t_u[1]); 00335 send_data.push_back(convertS.t_u[0]); 00336 00337 return send_data; 00338 } 00339
Generated on Tue Jul 12 2022 17:02:18 by 1.7.2