Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: NCP5623B GpsParser ISL29011 libmDot-mbed5 MTS-Serial MMA845x DOGS102 MPL3115A2
Mode/ModeGps.cpp
- Committer:
- jenkins@jenkinsdm1
- Date:
- 2019-03-14
- Revision:
- 16:e76cec0eec43
- Parent:
- 12:05435282f899
File content as of revision 16:e76cec0eec43:
/* Copyright (c) <2016> <MultiTech Systems>, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ModeGps.h"
#include "MTSLog.h"
#include "rtos.h"
#include "mbed.h"
#include "limits.h"
#define PACKETSIZE 11
ModeGps::ModeGps(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors, ModeJoin* join)
: Mode(lcd, buttons, dot, lora, gps, sensors),
_help(lcd),
_sem(lcd, _band),
_sem_join(lcd, _band),
_join(join)
{}
string ModeGps::intToString(int num){
char buf[4];
snprintf(buf, sizeof(buf), "%d", num);
return buf;
}
void ModeGps::init(){
//resets all parameters when re-entering mode
_interval = 5;
_padding = 0;
_power = 20;
_band = _dot->getFrequencyBand();
_parameter = POWER;
_drAll = false;
_link_check = false;
_GPS = false;
_sub_band = _dot->getFrequencySubBand();
_data_rate = _dot->getMinDatarate();
_dot->setTxDataRate(_data_rate);
_max_padding = _dot->getMaxPacketLength() - PACKETSIZE;
_Sw2 = "Power";
_Sw1 = intToString(_power);
_help.display();
osDelay(2000);
if (lora::ChannelPlan::IsPlanDynamic(_band)) {
_sem.display(_link_check, _snr, _rssi, _power, _sub_band, _padding, _data_rate);
_sem.initial();
_state = PARAMETERS;
_send_timer.start();
} else { _state = BAND_CHANGE;
_sem_join.displayEditFsb(_data_rate, _power, _sub_band, _dot->getNetworkName(), _dot->getNetworkPassphrase());
}
}
void ModeGps::drIncrement(){
_data_rate++;
//no fsk and japan data rates are different
if (_data_rate > _dot->getMaxDatarate() || _data_rate > mDot::DR6) {
_drAll = true;
_data_rate = _dot->getMinDatarate();
}
_dot->setTxDataRate(_data_rate);
logInfo("new data rate %s, POWER %lu", mDot::DataRateStr(_data_rate).c_str(), _power);
_max_padding = _dot->getMaxPacketLength() - PACKETSIZE;
}
void ModeGps::changeDataRate(){
if(_drAll) {
_data_rate = _dot->getMinDatarate() - 1;
_drAll = false;
}
drIncrement();
}
void ModeGps::changeParameter(){
_parameter++;
if(lora::ChannelPlan::IsPlanDynamic(_band) && _parameter == FSB){
_parameter++;
}
if(_parameter>INTERVAL){
_parameter = 0;
}
switch(_parameter) {
case DATA_RATE:
_Sw2 = "Data Rate";
_Sw1 = intToString(_data_rate);
if(_drAll){
_Sw1 = "All";
}
break;
case FSB:
_Sw2 = "FSB";
_Sw1 = intToString(_sub_band);
break;
case PADDING:
_Sw2 = "Padding";
_Sw1 = intToString(_padding);
break;
case POWER:
_Sw2 = "Power";
_Sw1 = intToString(_power);
break;
case INTERVAL:
_Sw2 = "Interval";
_Sw1 = intToString(_interval);
break;
default:
break;
}
}
void ModeGps::editParameter(){
switch(_parameter) {
case POWER:
if(_power<20){
_power+=3;
} else {
_power = 2;
}
_Sw1 = intToString(_power);
_dot->setTxPower(_power);
break;
case DATA_RATE:
changeDataRate();
if(_drAll) {
_Sw1="All";
} else {
_Sw1 = intToString(_data_rate);
}
break;
case FSB:
_send_timer.stop();
_send_timer.reset();
_state = BAND_CHANGE;
_dot->resetNetworkSession();
_lora->resetActivityLed();
_sem_join.displayEditFsb(mDot::DR0, 20, _sub_band, _dot->getNetworkName(), _dot->getNetworkPassphrase());
break;
case PADDING:
if(_padding<_max_padding){
_padding += 10 - (_padding % 10);
} else {
_padding = 0;
}
if(_padding>_max_padding){
_padding = _max_padding;
}
_Sw1 = intToString(_padding);
break;
default:
if(_interval<60){
_interval += 5;
} else {
_interval = 5;
}
_Sw1 = intToString(_interval);
break;
}
}
void ModeGps::formatData(){
_send_data.clear();
uint32_t lat = 0;
uint32_t lng = 0;
double degrees = 0;
double minutes = 0;
double seconds = 0;
_temp_C += 0.5;
if(_GPS) {
degrees = _latitude.degrees;
minutes = _latitude.minutes;
seconds = _latitude.seconds;
if(degrees<0) {
lat = ~(int)((degrees - minutes/60.0 - seconds/600000.0)*(-INT_MAX/90.0 + 1.5));
} else {
lat = (int)((degrees + minutes/60.0 + seconds/600000.0)*(INT_MAX/90.0 + 0.5));
}
degrees = _longitude.degrees;
minutes = _longitude.minutes;
seconds = _longitude.seconds;
if(degrees<0) {
lng = ~(int)((degrees - minutes/60.0 - seconds/600000.0)*(-INT_MAX/180.0 + 1.5));
} else {
lng = (int)((degrees + minutes/60.0 + seconds/600000.0)*(INT_MAX/180.0 + 0.5));
}
}
_send_data.push_back(0);
_send_data.push_back((int8_t) _temp_C);
_send_data.push_back(0);
for(int i=24; i>=0; i-=8){
_send_data.push_back((lat>>i)&0xFF);
}
for(int i=24; i>=0; i-=8){
_send_data.push_back((lng>>i)&0xFF);
}
for(int i=0; i<(_padding>_max_padding ? _max_padding:_padding); i++){
_send_data.push_back(0);
}
}
void ModeGps::setBand(){
_sub_band++;
if(_sub_band > mDot::FSB_8) _sub_band = mDot::FSB_ALL;
_dot->setFrequencySubBand(_sub_band);
}
void ModeGps::updateScreen(){
_temp_C = _sensors->getTemp(SensorHandler::CELSIUS);
if(_gps->getLockStatus() && _gps_available) {
_GPS = true;
_latitude = _gps->getLatitude();
_longitude = _gps->getLongitude();
_time = _gps->getTimestamp();
} else {
_GPS = false;
}
_sem.updateStats( _GPS, _longitude, _latitude, _time, _temp_C);
_sem.updateSw1(_Sw1, _Sw2);
_sem.updateSw2(_Sw2);
}
void ModeGps::send(){
_state = SENDING;
_send_timer.stop();
while(_dot->getNextTxMs()>0) {
_sem.updateNextCh((int)(_dot->getNextTxMs()/1000));
osDelay(250);
}
formatData();
_sem.sending();
_send_timer.reset();
_send_timer.start();
_lora->send(_send_data);
osDelay(500);
}
bool ModeGps::start(){
init();
_button_timer.start();
ButtonHandler::ButtonEvent be;
uint32_t e;
while (true) {
if(_state==PARAMETERS){
updateScreen();
}
e = osThreadFlagsWait(loraSignal | buttonSignal, osFlagsWaitAny, 250);
if (e == buttonSignal) {
be = _buttons->getButtonEvent();
switch(be) {
case ButtonHandler::sw1_press:
switch(_state) {
case BAND_CHANGE:
setBand();
_sem_join.updateJoinFsb(_sub_band);
break;
case PARAMETERS:
editParameter();
break;
default:
break;
}
break;
case ButtonHandler::sw2_press:
switch(_state) {
case BAND_CHANGE:
if(_join->start()){
_state = PARAMETERS;
_send_timer.start();
_sem.display(_link_check, _snr, _rssi, _power, _sub_band, _padding, DATA_RATE);
_sem.initial();
_dot->setTxDataRate(_data_rate);
} else _sem_join.displayEditFsb(mDot::DR0, 20, _sub_band, _dot->getNetworkName(), _dot->getNetworkPassphrase());
break;
case PARAMETERS:
changeParameter();
break;
default:
break;
}
break;
case ButtonHandler::sw1_hold:
_send_timer.stop();
_send_timer.reset();
return true;
default:
break;
}
}
if (e == loraSignal) {
_ls = _lora->getStatus();
switch (_ls) {
case LoRaHandler::send_success:
_sem.sendResult(" Send Sucess!");
osDelay(500);
_link_check = true;
_snr = _dot->getSnrStats();
_rssi = _dot->getRssiStats();
_button_timer.reset();
_state = PARAMETERS;
_sem.display(_link_check, _snr, _rssi, _power, _sub_band, _padding, _data_rate);
if(_drAll){
drIncrement();
}
break;
case LoRaHandler::send_failure:
_sem.sendResult(" Send Failed.");
osDelay(500);
_link_check = false;
_button_timer.reset();
_state = PARAMETERS;
_sem.display(_link_check, _snr, _rssi, _power, _sub_band, _padding, _data_rate);
if(_drAll){
drIncrement();
}
break;
case LoRaHandler::send_failure_payload:
_sem.sendResult("Payload too large");
osDelay(1000);
_sem.sendResult("Change Datarate");
osDelay(1000);
_link_check = false;
_button_timer.reset();
_state = PARAMETERS;
_sem.display(_link_check, _snr, _rssi, _power, _sub_band, _padding, _data_rate);
if(_drAll){
drIncrement();
}
break;
default:
break;
}
}
if(_send_timer.read_ms() > _interval*1000 && _button_timer.read_ms() > 3000){
send();
}
}
}