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 Mode.cpp Source File

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