diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a8fa48..19c14c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## Release 1.4 - Battery status now empty when Wio Battery chassis non connected - Non duty cycle zone now have 25s Duty Cycle instead of 5s ( preserve backend capacities ) +- Display the wio terminal name on boot (based on DEVEUI) +- Reduce communication period when the device is out of GPS coverage or not moving +- fix the bar display whith last value displayed on first column ## Release 1.3 - initialization of the change log \ No newline at end of file diff --git a/LoRaComE5.cpp b/LoRaComE5.cpp index afaa6f9..94729d1 100644 --- a/LoRaComE5.cpp +++ b/LoRaComE5.cpp @@ -463,6 +463,15 @@ uint32_t txDurationEstimate(uint8_t _dr) { // --------------------------------------------------------------------- // Manage transmission response asynchronously +// exemple : +// 12:23:29.618 -> AT+CMSGHEX=20591A02324505490C07 +// 12:23:29.721 -> +CMSGHEX: Start +// 12:23:29.721 -> +CMSGHEX: Wait ACK +// 12:23:33.559 -> +CMSGHEX: ACK Received +// 12:23:33.592 -> +CMSGHEX: PORT: 2; RX: "3E9999010101" +// 12:23:33.627 -> +CMSGHEX: RXWIN1, RSSI -84, SNR 6.0 +// 12:23:33.627 -> +CMSGHEX: Done + bool processTx(void) { if ( startsWith(loraContext.bufResponse,"+CMSGHEX: RXWIN*, RSSI") ) { int s = indexOf(loraContext.bufResponse,"RSSI "); @@ -524,6 +533,7 @@ bool processTx(void) { if ( sz == 6 && port == 2 ) { int downlinkSeqId = downlink[0]; //Serial.printf("Rx downlink for frame %d\r\n",downlinkSeqId); + // We search the previous one ... so it exists int idx = getIndexBySeq(downlinkSeqId); if ( idx != MAXBUFFER ) { state.worstRssi[idx] = downlink[1]; diff --git a/WioLoRaWanFieldTester.ino b/WioLoRaWanFieldTester.ino index 2f405d7..7760a47 100644 --- a/WioLoRaWanFieldTester.ino +++ b/WioLoRaWanFieldTester.ino @@ -87,7 +87,7 @@ void setup() { initState(); initScreen(); displayTitle(); - + // Specific build to clear the LoRa E5 memory storing the LoRa configuration // that allows firwmare update. #if defined JUSTCLEAN && HWTARGET == LORAE5 @@ -145,6 +145,7 @@ void setup() { clearScreen(); screenSetup(); analogReference(AR_INTERNAL2V23); + } @@ -203,7 +204,23 @@ void loop(void) { if ( cTime >= ( 1 * 60 * 1000 ) && canLoRaSend() ) fireMessage = true; break; case MODE_MAX_RATE: - if ( canLoRaSend() ) fireMessage = true; + #ifdef WITH_GPS + // join on start + if ( ( state.cState == NOT_JOINED || state.cState == JOIN_FAILED ) && canLoRaSend() ) fireMessage = true; + + // in case no GPS, we switch to 60s minimum + // for indoor test, manual mode can be use + if ( ! gps.isReady || ! gpsQualityIsGoodEnough() ) { + if ( cTime >= ( 1 * 60 * 1000 ) && canLoRaSend() ) fireMessage = true; + } else { + // check distance with the previous sent position + // under 50 meters we send messages on every minutes. + if ( gpsEstimateDistance() > 50 && canLoRaSend() ) fireMessage = true; + else if ( cTime >= ( 1 * 60 * 1000 ) && canLoRaSend() ) fireMessage = true; + } + #else + if ( canLoRaSend() ) fireMessage = true; + #endif break; } if ( state.cState == EMPTY_DWNLINK && canLoRaSend() ) { @@ -214,21 +231,26 @@ void loop(void) { // send a new test message on port 1, backend will create a downlink with information about network side reception cTime = 0; // Fill the frame - if ( gps.isReady && gpsQualityIsGoodEnough() ) { - uint64_t pos = gpsEncodePosition48b(); - myFrame[0] = (pos >> 40) & 0xFF; - myFrame[1] = (pos >> 32) & 0xFF; - myFrame[2] = (pos >> 24) & 0xFF; - myFrame[3] = (pos >> 16) & 0xFF; - myFrame[4] = (pos >> 8) & 0xFF; - myFrame[5] = (pos ) & 0xFF; - myFrame[6] = ((gps.altitude+1000) >> 8) & 0xFF; - myFrame[7] = ((gps.altitude+1000) ) & 0xFF; - myFrame[8] = (uint8_t)gps.hdop / 10; - myFrame[9] = gps.sats; - } else { + #ifdef WITH_GPS + if ( gps.isReady && gpsQualityIsGoodEnough() ) { + gpsBackupPosition(); + uint64_t pos = gpsEncodePosition48b(); + myFrame[0] = (pos >> 40) & 0xFF; + myFrame[1] = (pos >> 32) & 0xFF; + myFrame[2] = (pos >> 24) & 0xFF; + myFrame[3] = (pos >> 16) & 0xFF; + myFrame[4] = (pos >> 8) & 0xFF; + myFrame[5] = (pos ) & 0xFF; + myFrame[6] = ((gps.altitude+1000) >> 8) & 0xFF; + myFrame[7] = ((gps.altitude+1000) ) & 0xFF; + myFrame[8] = (uint8_t)gps.hdop / 10; + myFrame[9] = gps.sats; + } else { + bzero(myFrame, sizeof(myFrame)); + } + #else bzero(myFrame, sizeof(myFrame)); - } + #endif do_send(1, myFrame, sizeof(myFrame),getCurrentSf(), state.cPwr,true, state.cRetry); } loraLoop(); @@ -240,4 +262,5 @@ void loop(void) { if ( duration < 0 ) duration = 10; cTime += duration; batUpdateTime += duration; + } diff --git a/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.bin b/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.bin index 97ab57a..8d868b3 100755 Binary files a/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.bin and b/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.bin differ diff --git a/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.uf2 b/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.uf2 index 57b739c..8d23c1f 100644 Binary files a/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.uf2 and b/binaries/WioLoRaWANFieldTester_LoRaE5_ALLZONE.uf2 differ diff --git a/config.h b/config.h index 0481059..957fbf6 100644 --- a/config.h +++ b/config.h @@ -57,7 +57,7 @@ //#define JUSTCLEAN -#define VERSION "v1.4a" +#define VERSION "v1.4" #ifdef DEBUG #define LOGLN(x) Serial.println x @@ -79,6 +79,15 @@ #define LOGLORAF(x) #endif +#ifdef DEBUGGPS + #define LOGGPSLN(x) Serial.println x + #define LOGGPS(x) Serial.print x + #define LOGGPSF(x) Serial.printf x +#else + #define LOGGPSLN(x) + #define LOGGPS(x) + #define LOGGPSF(x) +#endif #define SERIALCONFIG Serial diff --git a/gps.cpp b/gps.cpp index 3fc9494..8d1e59d 100644 --- a/gps.cpp +++ b/gps.cpp @@ -115,9 +115,7 @@ void gpsLoop() { // Since this function change internal library var, // avoid multiple call, just once and use results later gps.lastNMEA = GPS.lastNMEA(); - #ifdef DEBUGGPS - Serial.print(gps.lastNMEA); - #endif + LOGGPS((gps.lastNMEA)); gps.rxStuff = true; if (!GPS.parse(gps.lastNMEA)) // this also sets the newNMEAreceived() flag to false return; // we can fail to parse a sentence in which case we should just wait for another @@ -159,6 +157,28 @@ void gpsLoop() { } +void gpsBackupPosition() { + gps.backupLongitude = gps.longitude; + gps.backupLatitude = gps.latitude; +} + + +// really low quality distance estimator +// return a result in meter +int gpsEstimateDistance() { + + int32_t dLon = gps.backupLongitude - gps.longitude; + int32_t dLat = gps.backupLatitude - gps.latitude; + if (dLon < 0) dLon = -dLon; + if (dLat < 0) dLat = -dLat; + dLon += dLat; + // we can estimate that a value of 100 = 1m + if ( dLon > 1000000 ) dLon = 1000000; // no need to be over 10km / preserve UI display in debug + return (dLon/100); + +} + + bool gpsQualityIsGoodEnough() { return (gps.isReady && gps.hdop < GPS_MAX_HDOP && gps.sats > GPS_MIN_SAT ); diff --git a/gps.h b/gps.h index b913fc8..a772408 100644 --- a/gps.h +++ b/gps.h @@ -30,6 +30,8 @@ void gpsSetup(); void gpsLoop(); uint64_t gpsEncodePosition48b(); bool gpsQualityIsGoodEnough(); +void gpsBackupPosition(); +int gpsEstimateDistance(); #ifdef DEBUGGPS char * gpsLastNMEA(); #endif @@ -50,6 +52,9 @@ typedef struct { int16_t altitude; // in meters uint8_t sats; // Number of sats used char * lastNMEA; // Last NMEA String received + + int32_t backupLongitude; // 1 / 10_000_000 + int32_t backupLatitude; // 1 / 10_000_000 } gpsData_t; diff --git a/testeur.cpp b/testeur.cpp index 77a5fb0..1d46377 100644 --- a/testeur.cpp +++ b/testeur.cpp @@ -28,12 +28,13 @@ #ifdef DEBUGDATA void initDebug() { int i = 0; - - state.rssi[i] = -120; state.snr[i] = -15 ; state.retry[i] = 1 ; state.seq[i] = i ; state.hs[i] = 2 ; state.bestRssi[i] = -80 ; state.worstRssi[i] = -130; state.minDistance[i] = 2500 ; state.maxDistance[i] = 15200;i++; - state.rssi[i] = 5; state.snr[i] = 15 ; state.retry[i] = 1 ; state.seq[i] = i ; state.hs[i] = NODATA ; state.bestRssi[i] = 0 ; state.worstRssi[i] = 0; state.minDistance[i] = 0 ; state.maxDistance[i] = 0;i++; - state.rssi[i] = NORSSI; state.snr[i] = NOSNR; state.retry[i] = LOSTFRAME ; state.seq[i] = i ; state.hs[i] = NODATA ; state.bestRssi[i] = 0 ; state.worstRssi[i] = 0; state.minDistance[i] = 0 ; state.maxDistance[i] = 0;i++; - state.rssi[i] = NORSSI; state.snr[i] = NOSNR; state.retry[i] = 1 ; state.seq[i] = i ; state.hs[i] = 1 ; state.bestRssi[i] = -110 ; state.worstRssi[i] = -110; state.minDistance[i] = 7000 ; state.maxDistance[i] = 7000;i++; - state.rssi[i] = -80; state.snr[i] = -2; state.retry[i] = 2 ; state.seq[i] = i ; state.hs[i] = 1 ; state.bestRssi[i] = -90 ; state.worstRssi[i] = -90; state.minDistance[i] = 30000 ; state.maxDistance[i] = 30000;i++; + for ( int k = 0 ; k < 6 ; k++) { // 30 on 32 + state.rssi[i] = -120; state.snr[i] = -15 ; state.retry[i] = 1 ; state.seq[i] = 100+(6*k)+i ; state.hs[i] = 2 ; state.bestRssi[i] = -80 ; state.worstRssi[i] = -130; state.minDistance[i] = 2500 ; state.maxDistance[i] = 15200;i++; + state.rssi[i] = 5; state.snr[i] = 15 ; state.retry[i] = 1 ; state.seq[i] = 100+(6*k)+i ; state.hs[i] = NODATA ; state.bestRssi[i] = 0 ; state.worstRssi[i] = 0; state.minDistance[i] = 0 ; state.maxDistance[i] = 0;i++; + state.rssi[i] = NORSSI; state.snr[i] = NOSNR; state.retry[i] = LOSTFRAME ; state.seq[i] = 100+(6*k)+i ; state.hs[i] = NODATA ; state.bestRssi[i] = 0 ; state.worstRssi[i] = 0; state.minDistance[i] = 0 ; state.maxDistance[i] = 0;i++; + state.rssi[i] = NORSSI; state.snr[i] = NOSNR; state.retry[i] = 1 ; state.seq[i] = 100+(6*k)+i ; state.hs[i] = 1 ; state.bestRssi[i] = -110 ; state.worstRssi[i] = -110; state.minDistance[i] = 7000 ; state.maxDistance[i] = 7000;i++; + state.rssi[i] = -80; state.snr[i] = -2; state.retry[i] = 2 ; state.seq[i] = 100+(6*k)+i ; state.hs[i] = 1 ; state.bestRssi[i] = -90 ; state.worstRssi[i] = -90; state.minDistance[i] = 30000 ; state.maxDistance[i] = 30000;i++; + } state.elements = i; state.writePtr = i; } @@ -84,24 +85,29 @@ void addInBuffer(int16_t rssi, int16_t snr, uint8_t retry, uint16_t seq, bool lo state.rssi[state.writePtr] = rssi; state.snr[state.writePtr] = snr; state.retry[state.writePtr] = retry; - state.hs[state.writePtr] = NODATA; } else { state.rssi[state.writePtr] = NORSSI; state.snr[state.writePtr] = NOSNR; state.retry[state.writePtr] = LOSTFRAME; - state.hs[state.writePtr] = NODATA; } + state.hs[state.writePtr] = NODATA; + state.worstRssi[state.writePtr] = NORSSI; + state.bestRssi[state.writePtr] = NORSSI; + state.minDistance[state.writePtr] = NODATA; + state.maxDistance[state.writePtr] = NODATA; + state.writePtr = (state.writePtr+1) & (MAXBUFFER-1); - if ( state.writePtr == state.readPtr ) { + if ( state.elements == MAXBUFFER ) { state.readPtr = (state.readPtr+1) & (MAXBUFFER-1); + } else { + state.elements++; } - if (state.elements < MAXBUFFER) state.elements++; } uint8_t getIndexInBuffer(int i) { int t = state.readPtr; + if ( i > state.elements ) return MAXBUFFER; for ( int k = 0 ; k < i ; k++ ) { - if ( t == state.writePtr ) return MAXBUFFER; t = (t+1) & (MAXBUFFER-1); } return t; @@ -109,7 +115,7 @@ uint8_t getIndexInBuffer(int i) { uint8_t getIndexBySeq(int seq) { int idx = state.readPtr; - while ( idx != state.writePtr && state.seq[idx] != seq ) { + while ( idx < state.elements && state.seq[idx] != seq ) { idx = ( idx + 1 ) & (MAXBUFFER-1); } if ( state.seq[idx] == seq ) return idx; @@ -117,12 +123,8 @@ uint8_t getIndexBySeq(int seq) { } uint8_t getLastIndexWritten() { - if ( state.writePtr == 0 ) { - if ( state.readPtr == 0 ) { - return MAXBUFFER; - } - return MAXBUFFER-1; - } + if ( state.elements == 0 ) return MAXBUFFER; + if ( state.writePtr == 0 ) return MAXBUFFER-1; return state.writePtr-1; } diff --git a/ui.cpp b/ui.cpp index 1f6d1b2..924d025 100644 --- a/ui.cpp +++ b/ui.cpp @@ -1101,7 +1101,7 @@ void refreshGpsDetails() { tft.setTextColor(TFT_RED); } - sprintf(sTmp,"Time: %02d:%02d:%02d", gps.hour, gps.minute, gps.second); + sprintf(sTmp,"Time: %02d:%02d:%02d", gps.hour, gps.minute, gps.second); tft.drawString(sTmp,TXT_ALL_OFF_X,TXT_TIME_OFF_Y,GFXFF); sprintf(sTmp,"Latitude: %f", gps.latitude/10000000.0); @@ -1110,7 +1110,11 @@ void refreshGpsDetails() { sprintf(sTmp,"Longitude: %f", gps.longitude/10000000.0); tft.drawString(sTmp,TXT_ALL_OFF_X,TXT_LNG_OFF_Y,GFXFF); - sprintf(sTmp,"Altitude: %d", gps.altitude); + #ifdef DEBUGGPS + sprintf(sTmp,"Altitude: %04d Dist: %d", gps.altitude,gpsEstimateDistance()); + #else + sprintf(sTmp,"Altitude: %d m", gps.altitude); + #endif tft.drawString(sTmp,TXT_ALL_OFF_X,TXT_ALT_OFF_Y,GFXFF); if ( gps.isReady && !gpsQualityIsGoodEnough() ) {