├── README.md └── spgpstrack.ino /README.md: -------------------------------------------------------------------------------- 1 | # spGPStrack - LoRaWAN GPS Mapping 2 | 3 | This program is a LoRaWAN GPS Tracker for mapping purposes 4 | It is developed for Arduino Uno with Dragino Lora/GPS Shield and for ESP32 TTGO T-Beam (tested with T22_V07) 5 | - configured as ABP so that you can power up the device at locations where you do not have coverage 6 | - will transmit the location all x meters 7 | - you can choose the payload format between CayenneLPP and a manual Payload Decoder Function 8 | - the software supports confirmed uplink and the Arduino will beep 9 | - You can read the GPS over Hardware Serial or Software Serial, so it's easier for development if you see what is going on during real operation 10 | - In case of Hardware Serial usage you can enable a Software Serial for debugging 11 | ## To Do 12 | - Timed transmission, which also executes when the tracker is not moving. For example every hour, to see if the tracker is still alive. 13 | - low power option 14 | - ~~ESP32 support [State: in work, see branch develop. The SPI Config produces backtraces] Hardware: ESP32 Uno, branded as Wemos~~ ESP32 already implemented fot TTGO T-Beam 15 | - Alternative WiFi Position for ESP32 16 | 17 | ## Quick Start 18 | - In the TTN Console, create an Application, register a new device (as ABP) 19 | - Copy the LoRaWAN Device Information and Keys into the sketch 20 | - Stack the boards and upload the sketch to board. To upload the sketch, you need to keep the Reset button on the Dragino pressed. 21 | (If you can upload without pressing that button, then this could be a sign that you have something wrong in the Dragino Jumpers or the Serial Settings of your sketch) 22 | - When you see the traffic in the TTN Console, you can proceed in configuring the Payload Decoder Function. 23 | - (if you do not see traffic in the TTN Console although you are sure that you are in good distance to a gateway, check the Frame Counter and the Dragino Jumpers) 24 | - Configure the TTNMapper-Integration, specify an Experiment Name for the time of the first try outs 25 | (or you will disclose your home location with a cloud of successfull connect dots) 26 | - You should find your new Experiment at the end of [this list](https://ttnmapper.org/experiments/list_all.php). 27 | 28 | ## ESP32 29 | For T22_07 30 | SPI Pin Setting Not Implemented in LMIC yet! -> https://github.com/matthijskooijman/arduino-lmic/issues/164 31 | 32 | -> Change the SPI Pins directly in the library 33 | 34 | **Attention!!! Don't forget to reset this, if you are using also other Hardware with LMIC** 35 | 36 | **hal.cpp** Line 79 37 | ```C 38 | static void hal_spi_init () { 39 | //SPI.begin(); 40 | SPI.begin(5,19,27); 41 | } 42 | ``` 43 | 44 | ## Dependencies 45 | - [Arduino LMIC](https://github.com/matthijskooijman/arduino-lmic) 46 | - [TinyGPS++](http://arduiniana.org/libraries/tinygpsplus/) 47 | - [CayenneLPP (Optional)](https://www.thethingsnetwork.org/docs/devices/arduino/api/cayennelpp.html) Install from Arduino Library Manager 48 | 49 | ## Configuration: 50 | - TXdist - defines, the distance [in meters], after which the position is sent 51 | - SF - Define The LoRaWAN Spreading Factor (DR_SF7 - DR_SF12) 7 and 8 recommended for mapping 52 | - SINGLE_CHANNEL - Only Use LoRaWAN Channel 0 for Single Channel Gateways 53 | - CONFIRMED - enables confirmed uplinks, ONLY Enable, if you conncect a Buzzer to Pin D5! Otherwise this feature is useless 54 | - SOFT_SERIAL - Uncomment to use Hardware Serial, otherwise Software Serial is used. In that case connect the GPS Module to RXpin and TXpin 55 | - DEBUG - If you use Hardware Serial you can enable DEBUG, to get Debug output on a Software Serial. Leave disabled to not use Software Serial at all 56 | - CAYENNELPP - If you want to use CayenneLPP as Payload Format otherwise use following Decoder Payload Function 57 | 58 | ## Payload Function 59 | ```javascript 60 | function Decoder(bytes, port) { 61 | var decoded = {}; 62 | // if (port === 1) decoded.led = bytes[0]; 63 | decoded.latitude = ((bytes[0]<<16)>>>0) + ((bytes[1]<<8)>>>0) + bytes[2]; 64 | decoded.latitude = (decoded.latitude / 16777215.0 * 180) - 90; 65 | decoded.longitude = ((bytes[3]<<16)>>>0) + ((bytes[4]<<8)>>>0) + bytes[5]; 66 | decoded.longitude= (decoded.longitude / 16777215.0 * 360) - 180; 67 | var altValue = ((bytes[6]<<8)>>>0) + bytes[7]; 68 | var sign = bytes[6] & (1 << 7); 69 | if(sign) 70 | { 71 | decoded.altitude = 0xFFFF0000 | altValue; 72 | } 73 | else 74 | { 75 | decoded.altitude = altValue; 76 | } 77 | decoded.hdop = bytes[8] / 10.0; 78 | return decoded; 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /spgpstrack.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * spGPStrack 3 | * Author: Samuel Puschacher 4 | * 5 | * Configuration: 6 | * TXdist - defines, the distance [in Meter], after which the position is sent 7 | * TXspeedModes - enable Speed Modes: You can transmit at different distances at different speeds 8 | * TXdistLOW - Transmit Interval distance in low speed mode 9 | * TXspeedLOW - Maximum speed for low speed mode 10 | * TXdistHIGH - Transmit Interval distance in high speed mode 11 | * TXspeedLOW - Minimum speed for high speed mode 12 | * SF - Define The LoRaWAN Spreading Factor (DR_SF7 - DR_SF12) 7 and 8 recommended for Mapping 13 | * CONFIRMED - enables Confirmed uplinks, ONLY Enable, if you conncect a Buzzer to Pin D5! Otherwise this Feature is useless 14 | * SOFT_SERIAL - Uncomment to use Hardware Serial, Otherwise Software Serial is used. In that case connect the GPS Module to RXpin and TXpin 15 | * DEBUG - If you use Hardware Serial you can enable DEBBUG, to get Debug outputon a Software Serial. Leave disabled to not use Software Serial at all 16 | * CAYENNELPP - If you want to use CayenneLPP as Payload Format otherwise use following Decoder Payload Function 17 | * Payload Decoder: 18 | 19 | function Decoder(bytes, port) { 20 | var decoded = {}; 21 | // if (port === 1) decoded.led = bytes[0]; 22 | decoded.latitude = ((bytes[0]<<16)>>>0) + ((bytes[1]<<8)>>>0) + bytes[2]; 23 | decoded.latitude = (decoded.latitude / 16777215.0 * 180) - 90; 24 | decoded.longitude = ((bytes[3]<<16)>>>0) + ((bytes[4]<<8)>>>0) + bytes[5]; 25 | decoded.longitude= (decoded.longitude / 16777215.0 * 360) - 180; 26 | var altValue = ((bytes[6]<<8)>>>0) + bytes[7]; 27 | var sign = bytes[6] & (1 << 7); 28 | if(sign) 29 | { 30 | decoded.altitude = 0xFFFF0000 | altValue; 31 | } 32 | else 33 | { 34 | decoded.altitude = altValue; 35 | } 36 | decoded.hdop = bytes[8] / 10.0; 37 | return decoded; 38 | } 39 | 40 | * 41 | */ 42 | 43 | /* TXdist in Meters */ 44 | #define TXdist 100 45 | // Enable Speed modes 46 | #define TXspeedModes 47 | /* Low Speed Mode */ 48 | // TX Distance in low speed mode; in meters 49 | #define TXdistLOW 50 50 | // max speed for low speed mode; in km/h 51 | #define TXspeedLOW 40 52 | /* High Speed Mode */ 53 | // TX Distance in high speed mode; in meters 54 | #define TXdistHIGH 250 55 | // min speed for high speed mode; in km/h 56 | #define TXspeedHIGH 80 57 | 58 | /* Define Region */ 59 | #define CFG_eu868 60 | /* Define Data Rate aka Sporeading Factor */ 61 | #define SF DR_SF7 62 | /* Single Channel Mode 63 | * Send only on Channel 0 64 | * To enable, Remove Comment ( // ) 65 | */ 66 | //#define SINGLE_CHANNEL 67 | 68 | /* Confirmed Uplinks 69 | * Set Value to 1 to enable 70 | * Set Value to 0 to disable 71 | */ 72 | #define CONFIRMED 0 73 | /* Software Serial Option 74 | * Read GPS from Software Serial 75 | * Uncomment to Enable 76 | */ 77 | //#define SOFT_SERIAL 78 | /* Set the IO Pins for the Software Serial */ 79 | #ifdef __AVR__ 80 | static const int RXPin = 4, TXPin = 3; 81 | #endif 82 | #ifdef ESP32 83 | #define BUILTIN_LED 21 84 | static const int RXPin = 12, TXPin = 13; 85 | HardwareSerial ESP_Serial(1); 86 | #endif 87 | #ifndef SOFT_SERIAL 88 | /* If you use Software Serial you can enable Debug Output over Pin A2 */ 89 | //#define DEBUG 90 | #endif 91 | 92 | /* Uncomment to use Cayenne LPP as Payload format*/ 93 | //#define CAYENNELPP 94 | 95 | 96 | /********************** End of Configuration **********************/ 97 | 98 | #if TXspeedLOW >= TXspeedHIGH 99 | #error "Overlapping speeds" 100 | #endif 101 | 102 | 103 | #include 104 | #include 105 | #ifdef __AVR__ 106 | #include 107 | #endif 108 | #ifdef ESP32 109 | #include 110 | Ticker tickerSampleGPS; 111 | #include 112 | #endif 113 | 114 | #include 115 | 116 | #ifdef SOFT_SERIAL 117 | #include 118 | #else 119 | #ifdef DEBUG 120 | #include 121 | #endif 122 | #endif 123 | 124 | #ifdef CAYENNELPP 125 | #include 126 | #endif 127 | 128 | static const uint32_t GPSBaud = 9600; 129 | 130 | // The TinyGPS++ object 131 | TinyGPSPlus gps; 132 | 133 | // The serial connection to the GPS device 134 | #ifdef SOFT_SERIAL 135 | SoftwareSerial ss(RXPin, TXPin); 136 | #else 137 | #ifdef DEBUG 138 | SoftwareSerial ds(A3, A2); 139 | #endif 140 | #endif 141 | 142 | #ifdef CAYENNELPP 143 | CayenneLPP lpp(20); 144 | #else 145 | uint8_t txBuffer[9]; 146 | #endif 147 | 148 | 149 | // ABP: 150 | 151 | // LoRaWAN end-device address (DevAddr, MSB) 152 | static const u4_t DEVADDR = 0x26000000 ; // <-- Change this address for every node! 153 | 154 | // LoRaWAN NwkSKey, network session key, MSB 155 | // This is the default Semtech key, which is used by the early prototype TTN 156 | // network. 157 | static const PROGMEM u1_t NWKSKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 158 | 159 | // LoRaWAN AppSKey, application session key, MSB 160 | // This is the default Semtech key, which is used by the early prototype TTN 161 | // network. 162 | static const u1_t PROGMEM APPSKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 163 | 164 | 165 | // These callbacks are only used in over-the-air activation, so they are 166 | // left empty here (we cannot leave them out completely unless 167 | // DISABLE_JOIN is set in config.h, otherwise the linker will complain). 168 | void os_getArtEui (u1_t* buf) { } 169 | void os_getDevEui (u1_t* buf) { } 170 | void os_getDevKey (u1_t* buf) { } 171 | 172 | static osjob_t sendjob; 173 | 174 | // Schedule TX every this many seconds (might become longer due to duty 175 | // cycle limitations). 176 | const unsigned TX_INTERVAL = 120; 177 | 178 | // Pin mapping Dragino Shield 179 | boolean lock = false; 180 | const int buzzer = 5; //buzzer to arduino pin 5 181 | 182 | #ifdef __AVR__ 183 | const lmic_pinmap lmic_pins = { 184 | .nss = 10, 185 | .rxtx = LMIC_UNUSED_PIN, 186 | .rst = 9, 187 | .dio = {2, 6, 7}, 188 | }; 189 | #endif 190 | #ifdef ESP32 191 | //Pin Mapping for TTGO T-BEAM 192 | const lmic_pinmap lmic_pins = { 193 | //.mosi = GPIO_NUM_27, 194 | //.miso = GPIO_NUM_19, 195 | //.sck = GPIO_NUM_5, 196 | /* For T22_07 197 | * SPI Pin Setting Not Implemented in LMIC yet! -> https://github.com/matthijskooijman/arduino-lmic/issues/164 198 | * Change the SPI Pins directly in the library 199 | * hal.cpp Line 79 200 | * static void hal_spi_init () { 201 | * //SPI.begin(); 202 | * SPI.begin(5,19,27); 203 | * } 204 | */ 205 | .nss = 18, 206 | .rxtx = LMIC_UNUSED_PIN, 207 | .rst = LMIC_UNUSED_PIN, 208 | .dio = {26, 33, 32}, 209 | }; 210 | 211 | #endif 212 | 213 | 214 | void onEvent (ev_t ev) { 215 | print(String(os_getTime())); 216 | print(": "); 217 | switch(ev) { 218 | case EV_SCAN_TIMEOUT: 219 | println(F("EV_SCAN_TIMEOUT")); 220 | break; 221 | case EV_BEACON_FOUND: 222 | println(F("EV_BEACON_FOUND")); 223 | break; 224 | case EV_BEACON_MISSED: 225 | println(F("EV_BEACON_MISSED")); 226 | break; 227 | case EV_BEACON_TRACKED: 228 | println(F("EV_BEACON_TRACKED")); 229 | break; 230 | case EV_JOINING: 231 | println(F("EV_JOINING")); 232 | break; 233 | case EV_JOINED: 234 | println(F("EV_JOINED")); 235 | break; 236 | case EV_RFU1: 237 | println(F("EV_RFU1")); 238 | break; 239 | case EV_JOIN_FAILED: 240 | println(F("EV_JOIN_FAILED")); 241 | break; 242 | case EV_REJOIN_FAILED: 243 | println(F("EV_REJOIN_FAILED")); 244 | break; 245 | case EV_TXCOMPLETE: 246 | println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); 247 | lock = false; 248 | if (LMIC.txrxFlags & TXRX_ACK){ 249 | println(F("Received ack")); 250 | // Give acutic Signal 251 | #ifdef __AVR__ 252 | tone(buzzer, 3000); // Send 3KHz sound signal... 253 | delay(500); 254 | noTone(buzzer); 255 | #endif 256 | } 257 | if (LMIC.dataLen) { 258 | println(F("Received ")); 259 | println(String(LMIC.dataLen)); 260 | println(F(" bytes of payload")); 261 | } 262 | // Schedule next transmission 263 | //os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); 264 | break; 265 | case EV_LOST_TSYNC: 266 | println(F("EV_LOST_TSYNC")); 267 | break; 268 | case EV_RESET: 269 | println(F("EV_RESET")); 270 | break; 271 | case EV_RXCOMPLETE: 272 | // data received in ping slot 273 | println(F("EV_RXCOMPLETE")); 274 | break; 275 | case EV_LINK_DEAD: 276 | println(F("EV_LINK_DEAD")); 277 | break; 278 | case EV_LINK_ALIVE: 279 | println(F("EV_LINK_ALIVE")); 280 | break; 281 | default: 282 | println(F("Unknown event")); 283 | break; 284 | } 285 | } 286 | 287 | void do_send(osjob_t* j){ 288 | #ifdef SINGLE_CHANNEL 289 | for (int i = 1; i<=8; i++) LMIC_disableChannel(i); 290 | #endif 291 | // Check if there is not a current TX/RX job running 292 | if (LMIC.opmode & OP_TXRXPEND) { 293 | println(F("OP_TXRXPEND, not sending")); 294 | } else { 295 | lock = true; 296 | 297 | // Prepare upstream data transmission at the next possible time. 298 | #ifdef CAYENNELPP 299 | // Set Transmission Data for CayenneLPP 300 | LMIC_setTxData2(3, lpp.getBuffer(), lpp.getSize(), CONFIRMED); 301 | #else 302 | // Set Transmission Data for Payload Function 303 | LMIC_setTxData2(3, txBuffer, sizeof(txBuffer), CONFIRMED); 304 | #endif 305 | #if CONFIRMED 306 | // No Retrys if no Confirmation, because we are moving 307 | LMIC.txCnt = TXCONF_ATTEMPTS; 308 | #endif 309 | println(F("Packet queued")); 310 | } 311 | // Next TX is scheduled after TX_COMPLETE event. 312 | } 313 | /* Println Function, which switches automaticaly between Hardware Serial / Software Serial / No debug output */ 314 | void println(String s) 315 | { 316 | #ifdef ESP32 317 | Serial.println(s); 318 | #else 319 | #ifdef SOFT_SERIAL 320 | // Debug output on Hardware Serial 321 | Serial.println(s); 322 | #else 323 | #ifdef DEBUG 324 | // Debug output on Software Serial 325 | ds.println(s); 326 | #endif 327 | #endif 328 | #endif 329 | } 330 | /* Print Function, which switches automaticaly between Hardware Serial / Software Serial / No debug output */ 331 | void print(String s) 332 | { 333 | #ifdef ESP32 334 | Serial.println(s); 335 | #else 336 | #ifdef SOFT_SERIAL 337 | // Debug output on Hardware Serial 338 | Serial.print(s); 339 | #else 340 | #ifdef DEBUG 341 | // Debug output on Software Serial 342 | ds.print(s); 343 | #endif 344 | #endif 345 | #endif 346 | } 347 | void setup() { 348 | #ifdef ESP32 349 | Serial.begin(115200); 350 | ESP_Serial.begin(GPSBaud, SERIAL_8N1, RXPin, TXPin); 351 | ESP_Serial.setTimeout(2); 352 | tickerSampleGPS.attach_ms(500, sampleGPS); 353 | #else 354 | #ifdef SOFT_SERIAL 355 | // Setup for Software Serial Option 356 | Serial.begin(115200); 357 | ss.begin(GPSBaud); 358 | #else 359 | // Setup for Hardware Serial Option 360 | Serial.begin(GPSBaud); 361 | #ifdef DEBUG 362 | // Setup Debug Serial 363 | ds.begin(115200); 364 | #endif 365 | #endif 366 | #endif 367 | println(F("Starting")); 368 | pinMode(buzzer, OUTPUT); 369 | 370 | print(F("TinyGPS++ library v. ")); println(TinyGPSPlus::libraryVersion()); 371 | 372 | 373 | // LMIC init 374 | os_init(); 375 | // Reset the MAC state. Session and pending data transfers will be discarded. 376 | LMIC_reset(); 377 | 378 | // Set static session parameters. Instead of dynamically establishing a session 379 | // by joining the network, precomputed session parameters are be provided. 380 | #ifdef PROGMEM 381 | // On AVR, these values are stored in flash and only copied to RAM 382 | // once. Copy them to a temporary buffer here, LMIC_setSession will 383 | // copy them into a buffer of its own again. 384 | uint8_t appskey[sizeof(APPSKEY)]; 385 | uint8_t nwkskey[sizeof(NWKSKEY)]; 386 | memcpy_P(appskey, APPSKEY, sizeof(APPSKEY)); 387 | memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY)); 388 | LMIC_setSession (0x1, DEVADDR, nwkskey, appskey); 389 | #else 390 | // If not running an AVR with PROGMEM, just use the arrays directly 391 | LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); 392 | #endif 393 | 394 | #if defined(CFG_eu868) 395 | // Set up the channels used by the Things Network, which corresponds 396 | // to the defaults of most gateways. Without this, only three base 397 | // channels from the LoRaWAN specification are used, which certainly 398 | // works, so it is good for debugging, but can overload those 399 | // frequencies, so be sure to configure the full frequency range of 400 | // your network here (unless your network autoconfigures them). 401 | // Setting up channels should happen after LMIC_setSession, as that 402 | // configures the minimal channel set. 403 | // NA-US channels 0-71 are configured automatically 404 | LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 405 | LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band 406 | LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 407 | LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 408 | LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 409 | LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 410 | LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 411 | LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band 412 | LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band 413 | // TTN defines an additional channel at 869.525Mhz using SF9 for class B 414 | // devices' ping slots. LMIC does not have an easy way to define set this 415 | // frequency and support for class B is spotty and untested, so this 416 | // frequency is not configured here. 417 | #elif defined(CFG_us915) 418 | // NA-US channels 0-71 are configured automatically 419 | // but only one group of 8 should (a subband) should be active 420 | // TTN recommends the second sub band, 1 in a zero based count. 421 | // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json 422 | LMIC_selectSubBand(1); 423 | #endif 424 | 425 | // Disable link check validation 426 | LMIC_setLinkCheckMode(0); 427 | 428 | // TTN uses SF9 for its RX2 window. 429 | LMIC.dn2Dr = DR_SF9; 430 | 431 | // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library) 432 | LMIC_setDrTxpow(SF,14); 433 | println("Setup OK"); 434 | } 435 | 436 | void loop() { 437 | 438 | os_runloop_once(); 439 | // Don't check gps during LMIC sending 440 | if(!lock){ 441 | #ifndef ESP32 442 | smartDelay(70); 443 | #endif 444 | } 445 | static double LAST_TX_LAT = 0, LAST_TX_LON = 0; 446 | static float LAST_COURSE = -1; 447 | static boolean doDouble = false; 448 | static unsigned int fix = 0; 449 | // Check if transmission can Be done (GPS Fix and Precision) 450 | if( gps.location.isValid() && gps.hdop.isValid() && gps.sentencesWithFix() > fix && gps.hdop.hdop() > 0 && gps.hdop.hdop() < 5 && !lock ){ 451 | printf("Valid GPS"); 452 | // Set current GPS fix Count 453 | fix = gps.sentencesWithFix(); 454 | // Measure Distance to Last Transmission Point 455 | unsigned long lastTxDist = 456 | (unsigned long)TinyGPSPlus::distanceBetween( 457 | gps.location.lat(), 458 | gps.location.lng(), 459 | LAST_TX_LAT, 460 | LAST_TX_LON); 461 | println("Last TX Distance " + String(lastTxDist) + "m"); 462 | // Calculate Course to last transmission 463 | double lastTxCourse = 464 | TinyGPSPlus::courseTo( 465 | gps.location.lat(), 466 | gps.location.lng(), 467 | LAST_TX_LAT, 468 | LAST_TX_LON); 469 | 470 | //println( "Course: " + String(lastTxCourse)); 471 | 472 | // If Distance to last TX Point is bigger than the TXdistance Prepare and Trigger Data Transmission 473 | bool transmit = false; 474 | #ifndef TXspeedModes 475 | transmit = lastTxDist > TXdist; // No speed modes, Default TX distance 476 | #else 477 | transmit = 478 | ( (gps.speed.kmph() <= TXspeedLOW ) && (lastTxDist > TXdistLOW) ) || // Low speed mode Check 479 | ( (gps.speed.kmph() >= TXspeedHIGH ) && (lastTxDist > TXdistHIGH) ) || //High speed mode chek 480 | (lastTxDist > TXdist); // Default TX distance 481 | #endif 482 | if( transmit ){ 483 | #ifdef DOUBLE_SEND 484 | doDouble!=doDouble; 485 | #endif 486 | #ifdef CAYENNELPP 487 | // Data Preperation for Cayenne LPP 488 | lpp.reset(); 489 | lpp.addGPS(0, float(gps.location.lat()), float(gps.location.lng()), gps.altitude.meters()); 490 | lpp.addDigitalInput(1, uint8_t(lastTxDist)); 491 | #else 492 | // Data preperation for Payload Function 493 | uint8_t hdop; 494 | uint16_t alt; 495 | uint32_t flat, flon; 496 | flat = ((gps.location.lat() + 90) / 180) * 16777215; 497 | flon = ((gps.location.lng() + 180) / 360) * 16777215; 498 | txBuffer[0] = ( flat >> 16 ) & 0xFF; 499 | txBuffer[1] = ( flat >> 8 ) & 0xFF; 500 | txBuffer[2] = flat & 0xFF; 501 | 502 | txBuffer[3] = ( flon >> 16 ) & 0xFF; 503 | txBuffer[4] = ( flon >> 8 ) & 0xFF; 504 | txBuffer[5] = flon & 0xFF; 505 | 506 | alt = gps.altitude.meters(); 507 | txBuffer[6] = ( alt >> 8 ) & 0xFF; 508 | txBuffer[7] = alt & 0xFF; 509 | 510 | hdop = gps.hdop.hdop()*10; 511 | txBuffer[8] = hdop & 0xFF; 512 | #endif 513 | // Set Last TX Point to the Current Position 514 | LAST_TX_LAT = gps.location.lat(); 515 | LAST_TX_LON = gps.location.lng(); 516 | //Do the send Function 517 | do_send(&sendjob); 518 | } 519 | 520 | } 521 | else { 522 | // Get Alternative Position 523 | #ifdef ESP32 524 | 525 | 526 | #endif 527 | } 528 | } 529 | 530 | // GPS Parsing Function 531 | static void sampleGPS(){ 532 | #ifdef ESP32 533 | while (ESP_Serial.available()) 534 | #else 535 | #ifdef SOFT_SERIAL 536 | while (ss.available()) 537 | #else 538 | while (Serial.available()) 539 | #endif 540 | #endif 541 | { 542 | #ifdef ESP32 543 | //println("GPS"); 544 | gps.encode(ESP_Serial.read()); 545 | #else 546 | #ifdef SOFT_SERIAL 547 | gps.encode(ss.read()); 548 | #else 549 | gps.encode(Serial.read()); 550 | //ds.println("a " + Serial.read()); 551 | #endif 552 | #endif 553 | } 554 | //Serial.println(ss.read()); 555 | 556 | } 557 | static void smartDelay(unsigned long ms) 558 | { 559 | unsigned long start = millis(); 560 | do 561 | { 562 | sampleGPS(); 563 | } while (millis() - start < ms); 564 | } 565 | --------------------------------------------------------------------------------