First version (beta) of a GPS application for the QW GPS shield that does its own NMEA parsing. It sends out gps data in the TD_GEOLOCATION format, but replaces the first byte with the temperature. Note that some features of the NMEA library are untested.

Dependencies:   QW_NMEA QW_Sensors mbed

Firmware

This program starts the GPS on the TD1204 in continuous navigating mode using the following AT-command:

AT$GPS=1,16,0,65535,1,1

A NMEA message parser decodes the data coming from the UBX G7020 GPS-receiver inside the TD1204. A timer sends the latests gps fix and temperature every 15 minutes to the SIGFOX backend or whenever a button is pressed.

Sending 'a' through the virtual com port, sends a TD_GEOLOCATION packet without modifications (so without temperature). The command sent to the TD1204 is: AT$GSND

  • LED0 toggles every second.
  • LED2 burns when a GPS position is sent without a position fix.
  • LED3 burns when a GPS position is sent with a valid fix.

The GPS packet is a modified version of a standard TD_GEOLOCATION packet. This allows a the temperature to be sent along with the GPS position.

How to decode a TD_GEOLOCATION GPS frame

Here is how to decode the data contained into this frame:

frame example: 1701010005bb688ddd602590

  • [0x17] byte 1: temperature in °C, stored as a signed char. In this example this is 0x17 which corresponds to 23°C.
    A negative temperature example: 0xE9 represents -23°C. Only in this modified TD_GEOLOCATION frame
  • [0x0] nibble 3: reserved for future use.
  • [0x1010] nibble 4-7: This part tells you this is a GPS frame encoded according to GPS_DATA_XYZ_SV_HDOP.
  • [0x005bb688ddd6] nibble 8-19: This part contains the position and should be decoded like this:
    0x005bb688ddd6 = 393904446934 (decimal) => 00°39.390' 44°46.934' (longitude ; latitude)
  • [0x025] 12 bits for the altitude x 2 meters. In this case 0x025 = 37*2= 74 meters.
  • [0x90] = 10010000 in binary.
    - 1 bit for longitude sign ( 0 = positive, 1 = negative) => 1 => -00°39.390'
    - 1 bit for latitude sign ( 0 = positive, 1 = negative) => 0 => +44°46.934'
    - 1 bit for altitude sign ( 0 =positive, 1 = negative) => 0 => +74 meters
    - 3 bits for satellites in view => 4
    - 2 bits for overall horizontal dilution of precision going from 0 (very good) to 3 (bad).

Settings in the SIGFOX backend

Create a new device-type and set display typte to Geolocation > Telecom Design.

/media/uploads/quicksand/gpsdecode.jpg

Assign your development kit to this device-type and the decoding will happen automatically:

/media/uploads/quicksand/gpsdecoded.jpg

Data if no GPS fix was found!

Note: The data looks like this if your device didn't get a valid fix before the transmission of a SIGFOX packet.

/media/uploads/quicksand/nofix.jpg

You can follow the NMEA messages of the GPS if you open up a terminal and connect to the virtual com-port of the QW shield. More info about NMEA messages can be found HERE.

/media/uploads/quicksand/nmea.jpg

GPS data is displayed in different message formats over a serial interface. There are standard and non-standard (proprietary) message formats. Nearly all GPS receivers output NMEA data. The NMEA standard is formatted in lines of data called sentences. Each sentence contains various bits of data organized in comma delimited format (i.e. data separated by commas). Here’s example NMEA sentences from a GPS receiver with satellite lock (4+ satellites, accurate position):

$GPRMC,235316.000,A,4003.9040,N,10512.5792,W,0.09,144.75,141112,,*19
$GPGGA,235317.000,4003.9039,N,10512.5793,W,1,08,1.6,1577.9,M,-20.7,M,,0000*5F
$GPGSA,A,3,22,18,21,06,03,09,24,15,,,,,2.5,1.6,1.9*3E

For example, the GPGGA sentence above contains the following:

  • Time: 235317.000 is 23:53 and 17.000 seconds in Greenwich mean time
  • Longitude: 4003.9040,N is latitude in degrees.decimal minutes, north
  • Latitude: 10512.5792,W is longitude in degrees.decimal minutes, west
  • Number of satellites seen: 08
  • Altitude: 1577 meters

More information about the NMEA sentences coming from the TD1204 can be found in the following datasheet of the u-blox 7 series: Link.

You can even open up a track of your device:

/media/uploads/quicksand/track.jpg

/media/uploads/quicksand/trackmap.jpg

More information and other example code can be found on the component page by clicking the link below: https://developer.mbed.org/components/QW-SIGFOX-Development-Kit/

Files at this revision

API Documentation at this revision

Comitter:
quicksand
Date:
Wed May 18 14:53:38 2016 +0000
Child:
1:5fc0fcda6aae
Commit message:
First version of a gps application that does its own NMEA parsing and adds the temperature (signed char) in the first byte of a TD_GEOLOCATION GPS packet.

Changed in this revision

QW_NMEA.lib Show annotated file Show diff for this revision Revisions of this file
QW_Sensors.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QW_NMEA.lib	Wed May 18 14:53:38 2016 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/quicksand/code/QW_NMEA/#67f22e813b74
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QW_Sensors.lib	Wed May 18 14:53:38 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/quicksand/code/QW_Sensors/#1b27ad5eb94a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed May 18 14:53:38 2016 +0000
@@ -0,0 +1,176 @@
+#include "mbed.h"
+#include "GPS.h"
+#include "LinearTempSensor.h"
+#define updateinterval  30
+
+DigitalOut LED_0 (PB_6);
+DigitalOut LED_1 (PA_7);
+DigitalOut LED_2 (PA_6);
+DigitalOut LED_3 (PA_5);
+InterruptIn SW1(PB_10);
+InterruptIn SW2(PA_8);
+
+Ticker hartbeat;
+Ticker position_update;
+
+//Virtual serial port over USB
+Serial pc(USBTX, USBRX);
+Serial modem(PA_9, PA_10);
+GPS gps(PA_9, PA_10);
+
+/*Temperature sensor */
+LinearTempSensor sensor(PA_0, 10);
+signed char      temperature;         // Temperature in signed char.
+
+
+void sertmout();
+bool modem_command_check_ok(char * command);
+void modem_setup();
+
+uint32_t txtimeout = 0;
+
+bool ser_timeout = false;
+
+
+// Blinking LED Ticker
+void beat()
+{
+    LED_0 = !LED_0;
+    txtimeout++;
+}
+
+void sw1interrupt()
+{
+    txtimeout = updateinterval+1; // instantly send
+}
+
+void sw2interrupt()
+{
+    txtimeout = updateinterval+1; // instantly send
+}
+
+int main()
+{
+    wait(3);
+    modem_setup();
+    float vOut = sensor.Sense();
+    pc.printf("\n\rMCP9700 reading:  Vout: %.2f mV\n\r", vOut);
+    LED_0 = 1;
+    LED_1 = 1;
+    LED_2 = 1;
+    LED_3 = 1;
+    hartbeat.attach(&beat, 1);
+    SW2.fall(&sw1interrupt);
+    SW1.fall(&sw2interrupt);
+    while(!modem_command_check_ok("AT$GPS=1,16,0,65535,1,1\n")) pc.printf("Trying to start GPS...\r\n");
+    pc.printf("GPS started!\r\n");
+    while(1) {
+        if(pc.readable()) {
+            if (pc.getc() == 'a')
+                modem_command_check_ok("AT$GSND\n");
+        }
+        int result = gps.sample();
+        if(result != NO_LOCK) {
+            if((result == RMC && gps.gprmc_status == 'A')) {
+                if(txtimeout > updateinterval) {
+                    LED_3 = 0;
+                    hartbeat.detach();
+                    sensor.Sense();
+                    temperature = (signed char)rint(sensor.GetAverageTemp());
+                    pc.printf("\r\nGPRMC Fix: latitude: %f, longitude: %f Temperature: %d\r\n",gps.get_dec_latitude(),gps.get_dec_longitude(),temperature);
+                    char sfcommand[128];
+                    sprintf(sfcommand, "AT$SF=%02x%s,2,0\n", temperature & 0xff,gps.get_nmea_to_td()); // Remark & 0xff needed to limit the value to two bytes!
+                    modem_command_check_ok(sfcommand);
+                    txtimeout = 0;
+                    LED_3 = 1;
+                    hartbeat.attach(&beat, 1);
+                }
+            } else if(txtimeout > updateinterval+5) { // 5 seconds extra in case of no fix (why? -> we're only waiting for GPRMC messages and we may have just skipped one)
+                LED_2 = 0;
+                hartbeat.detach();
+                sensor.Sense();
+                temperature = (signed char)rint(sensor.GetAverageTemp());
+                pc.printf("\r\nNo GPRMC Fix! (sending 0xffff... as position data) Temperature: %d\r\n",temperature);
+                char sfcommand[128];
+                sprintf(sfcommand, "AT$SF=%02x01010fffffffffffffffff,2,0\n", temperature & 0xff); // Remark & 0xff needed to limit the value to two bytes!
+                modem_command_check_ok(sfcommand);
+                txtimeout = 0;
+                LED_2 = 1;
+                hartbeat.attach(&beat, 1);
+            }
+        } else if(txtimeout > updateinterval+5) { // 5 seconds extra in case of no fix (why? -> we're only waiting for GPRMC messages and we may have just skipped one)
+            LED_2 = 0;
+            hartbeat.detach();
+            sensor.Sense();
+            temperature = (signed char)rint(sensor.GetAverageTemp());
+            pc.printf("\r\nNo GPRMC Fix! (sending 0xffff... as position data) Temperature: %d\r\n",temperature);
+            char sfcommand[128];
+            sprintf(sfcommand, "AT$SF=%02x01010fffffffffffffffff,2,0\n", temperature & 0xff); // Remark & 0xff needed to limit the value to two bytes!
+            modem_command_check_ok(sfcommand);
+            txtimeout = 0;
+            LED_2 = 1;
+            hartbeat.attach(&beat, 1);
+        }
+    }
+}
+
+void modem_setup()
+{
+    /* Reset to factory defaults */
+    if(modem_command_check_ok("AT&F")) {
+        pc.printf("Factory reset succesfull\r\n");
+    } else {
+        pc.printf("Factory reset TD120x failed\r\n");
+    }
+    /* Disable local echo */
+    modem.printf("ATE0\n");
+    if(modem_command_check_ok("ATE0")) {
+        pc.printf("Local echo disabled\r\n");
+    }
+    /* Write to mem */
+    if(modem_command_check_ok("AT&W")) {
+        pc.printf("Settings saved!\r\n");
+    }
+}
+
+/* ISR for serial timeout */
+void sertmout()
+{
+    ser_timeout = true;
+}
+
+bool modem_command_check_ok(char * command)
+{
+    /* first clear serial data buffers */
+    while(modem.readable()) modem.getc();
+    /* Timeout for response of the modem */
+    Timeout tmout;
+    ser_timeout = false;
+    /* Buffer for incoming data */
+    char responsebuffer[6];
+    /* Flag to set when we get 'OK' response */
+    bool ok = false;
+    bool error = false;
+    /* Print command to TD120x */
+    modem.printf(command);
+    /* Newline to activate command */
+    modem.printf("\n");
+    /* Wait untill serial feedback, max 3 seconds before timeout */
+    tmout.attach(&sertmout, 3.0);
+    while(!modem.readable()&& ser_timeout == false);
+    while(!ok && !ser_timeout && !error) {
+        if(modem.readable()) {
+            for(int i = 0; i < 5; i++) {
+                responsebuffer[i] = responsebuffer[i+1];
+            }
+            responsebuffer[5] = modem.getc();
+            if(responsebuffer[0] == '\r' && responsebuffer[1] == '\n' && responsebuffer[2] == 'O' && responsebuffer[3] == 'K' && responsebuffer[4] == '\r' && responsebuffer[5] == '\n' ) {
+                ok = true;
+            } else if(responsebuffer[0] == '\r' && responsebuffer[1] == '\n' && responsebuffer[2] == 'E' && responsebuffer[3] == 'R' && responsebuffer[4] == 'R' && responsebuffer[5] == 'O' ) {
+                error = true;
+            }
+        }
+    }
+    tmout.detach();
+    return ok;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed May 18 14:53:38 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/7c328cabac7e
\ No newline at end of file