From d3e9dbf6a9c7e3a44adaf76f84167d16f6516e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Oct 2022 16:37:38 +0200 Subject: [PATCH] Add NMEA output mode (my own position, and other devices as waypoints) to serial module --- src/gps/NMEAWPL.cpp | 50 ++++++++++++++++++++++++++++++++++++ src/gps/NMEAWPL.h | 1 + src/modules/SerialModule.cpp | 47 +++++++++++++++++++++++++-------- src/modules/SerialModule.h | 3 +++ 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/gps/NMEAWPL.cpp b/src/gps/NMEAWPL.cpp index bc0ff6ec7..2d87a4149 100644 --- a/src/gps/NMEAWPL.cpp +++ b/src/gps/NMEAWPL.cpp @@ -12,6 +12,7 @@ * 4 E or W (East or West) * 5 Waypoint name * 6 Checksum + * ------------------------------------------- */ uint printWPL(char *buf, Position &pos, const char *name) @@ -24,3 +25,52 @@ uint printWPL(char *buf, Position &pos, const char *name) len += sprintf(buf + len, "*%02X\r\n", chk); return len; } + +/* ------------------------------------------- + * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * | | | | | | | | | | | | | | | + * $--GGA,hhmmss.ss,ddmm.mm,a,ddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh + * + * Field Number: + * 1 UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds. + * 2 Latitude + * 3 N or S (North or South) + * 4 Longitude + * 5 E or W (East or West) + * 6 GPS Quality Indicator (non null) + * 7 Number of satellites in use, 00 - 12 + * 8 Horizontal Dilution of precision (meters) + * 9 Antenna Altitude above/below mean-sea-level (geoid) (in meters) + * 10 Units of antenna altitude, meters + * 11 Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid + * 12 Units of geoidal separation, meters + * 13 Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used + * 14 Differential reference station ID, 0000-1023 + * 15 Checksum + * ------------------------------------------- + */ + +uint printGGA(char *buf, Position &pos) +{ + uint len = sprintf(buf, "$GNGGA,%06d.%03d,%07.2f,%c,%08.2f,%c,%d,%02d,%04d,%04d,%c,%04d,%c,%d,%04d", + pos.time / 1000, + pos.time % 1000, + pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', + pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', + pos.fix_type, + pos.sats_in_view, + pos.HDOP, + pos.altitude, + 'M', + pos.altitude_geoidal_separation, + 'M', + 0, + 0); + + uint chk = 0; + for (uint i = 1; i < len; i++) { + chk ^= buf[i]; + } + len += sprintf(buf + len, "*%02X\r\n", chk); + return len; +} \ No newline at end of file diff --git a/src/gps/NMEAWPL.h b/src/gps/NMEAWPL.h index 07016ef23..1c0ef5de3 100644 --- a/src/gps/NMEAWPL.h +++ b/src/gps/NMEAWPL.h @@ -4,3 +4,4 @@ #include "main.h" uint printWPL(char *buf, Position &pos, const char *name); +uint printGGA(char *buf, Position &pos); diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 59f489d52..05ed44cd7 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -2,6 +2,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" +#include "NMEAWPL.h" #include "Router.h" #include "configuration.h" #include @@ -40,7 +41,7 @@ KNOWN PROBLEMS * Until the module is initilized by the startup sequence, the TX pin is in a floating state. Device connected to that pin may see this as "noise". - * Will not work on NRF and the Linux device targets. + * Will not work on T-Echo and the Linux device targets. */ @@ -62,16 +63,19 @@ char serialStringChar[Constants_DATA_PAYLOAD_LEN]; SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio") { - // restrict to the admin channel for rx - boundChannel = Channels::serialChannel; switch (moduleConfig.serial.mode) { case ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG: ourPortNum = PortNum_TEXT_MESSAGE_APP; break; + case ModuleConfig_SerialConfig_Serial_Mode_NMEA: + ourPortNum = PortNum_POSITION_APP; + break; default: ourPortNum = PortNum_SERIAL_APP; + // restrict to the serial channel for rx + boundChannel = Channels::serialChannel; break; } } @@ -175,15 +179,25 @@ int32_t SerialModule::runOnce() firstTime = 0; } else { - String serialString; - while (Serial2.available()) { - serialString = Serial2.readString(); - serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN); + // in NMEA mode send out GGA every 2 seconds, Don't read from Port + if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { + if (millis() - lastNmeaTime > 2000) { + lastNmeaTime = millis(); + printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position); + Serial2.printf("%s", outbuf); + } + } else { + String serialString; - serialModuleRadio->sendPayload(); + while (Serial2.available()) { + serialString = Serial2.readString(); + serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN); - DEBUG_MSG("Received: %s\n", serialStringChar); + serialModuleRadio->sendPayload(); + + DEBUG_MSG("Received: %s\n", serialStringChar); + } } } @@ -191,7 +205,7 @@ int32_t SerialModule::runOnce() } else { DEBUG_MSG("Serial Module Disabled\n"); - return (INT32_MAX); + return INT32_MAX; } #else return INT32_MAX; @@ -255,6 +269,19 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { // TODO this needs to be implemented + } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { + // Decode the Payload some more + Position scratch; + Position *decoded = NULL; + if (mp.which_payload_variant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) { + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, Position_fields, &scratch)) { + decoded = &scratch; + } + // send position packet as WPL to the serial port + printWPL(outbuf, *decoded, nodeDB.getNode(getFrom(&mp))->user.long_name); + Serial2.printf("%s", outbuf); + } } } diff --git a/src/modules/SerialModule.h b/src/modules/SerialModule.h index e93cb5952..0130bbe2d 100644 --- a/src/modules/SerialModule.h +++ b/src/modules/SerialModule.h @@ -11,6 +11,8 @@ class SerialModule : private concurrency::OSThread { bool firstTime = 1; + unsigned long lastNmeaTime = millis(); + char outbuf[90] = ""; public: SerialModule(); @@ -28,6 +30,7 @@ extern SerialModule *serialModule; class SerialModuleRadio : public MeshModule { uint32_t lastRxID = 0; + char outbuf[90] = ""; public: SerialModuleRadio();