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/

Committer:
quicksand
Date:
Wed May 18 14:53:38 2016 +0000
Revision:
0:56230ba3cdeb
Child:
1:5fc0fcda6aae
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.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
quicksand 0:56230ba3cdeb 1 #include "mbed.h"
quicksand 0:56230ba3cdeb 2 #include "GPS.h"
quicksand 0:56230ba3cdeb 3 #include "LinearTempSensor.h"
quicksand 0:56230ba3cdeb 4 #define updateinterval 30
quicksand 0:56230ba3cdeb 5
quicksand 0:56230ba3cdeb 6 DigitalOut LED_0 (PB_6);
quicksand 0:56230ba3cdeb 7 DigitalOut LED_1 (PA_7);
quicksand 0:56230ba3cdeb 8 DigitalOut LED_2 (PA_6);
quicksand 0:56230ba3cdeb 9 DigitalOut LED_3 (PA_5);
quicksand 0:56230ba3cdeb 10 InterruptIn SW1(PB_10);
quicksand 0:56230ba3cdeb 11 InterruptIn SW2(PA_8);
quicksand 0:56230ba3cdeb 12
quicksand 0:56230ba3cdeb 13 Ticker hartbeat;
quicksand 0:56230ba3cdeb 14 Ticker position_update;
quicksand 0:56230ba3cdeb 15
quicksand 0:56230ba3cdeb 16 //Virtual serial port over USB
quicksand 0:56230ba3cdeb 17 Serial pc(USBTX, USBRX);
quicksand 0:56230ba3cdeb 18 Serial modem(PA_9, PA_10);
quicksand 0:56230ba3cdeb 19 GPS gps(PA_9, PA_10);
quicksand 0:56230ba3cdeb 20
quicksand 0:56230ba3cdeb 21 /*Temperature sensor */
quicksand 0:56230ba3cdeb 22 LinearTempSensor sensor(PA_0, 10);
quicksand 0:56230ba3cdeb 23 signed char temperature; // Temperature in signed char.
quicksand 0:56230ba3cdeb 24
quicksand 0:56230ba3cdeb 25
quicksand 0:56230ba3cdeb 26 void sertmout();
quicksand 0:56230ba3cdeb 27 bool modem_command_check_ok(char * command);
quicksand 0:56230ba3cdeb 28 void modem_setup();
quicksand 0:56230ba3cdeb 29
quicksand 0:56230ba3cdeb 30 uint32_t txtimeout = 0;
quicksand 0:56230ba3cdeb 31
quicksand 0:56230ba3cdeb 32 bool ser_timeout = false;
quicksand 0:56230ba3cdeb 33
quicksand 0:56230ba3cdeb 34
quicksand 0:56230ba3cdeb 35 // Blinking LED Ticker
quicksand 0:56230ba3cdeb 36 void beat()
quicksand 0:56230ba3cdeb 37 {
quicksand 0:56230ba3cdeb 38 LED_0 = !LED_0;
quicksand 0:56230ba3cdeb 39 txtimeout++;
quicksand 0:56230ba3cdeb 40 }
quicksand 0:56230ba3cdeb 41
quicksand 0:56230ba3cdeb 42 void sw1interrupt()
quicksand 0:56230ba3cdeb 43 {
quicksand 0:56230ba3cdeb 44 txtimeout = updateinterval+1; // instantly send
quicksand 0:56230ba3cdeb 45 }
quicksand 0:56230ba3cdeb 46
quicksand 0:56230ba3cdeb 47 void sw2interrupt()
quicksand 0:56230ba3cdeb 48 {
quicksand 0:56230ba3cdeb 49 txtimeout = updateinterval+1; // instantly send
quicksand 0:56230ba3cdeb 50 }
quicksand 0:56230ba3cdeb 51
quicksand 0:56230ba3cdeb 52 int main()
quicksand 0:56230ba3cdeb 53 {
quicksand 0:56230ba3cdeb 54 wait(3);
quicksand 0:56230ba3cdeb 55 modem_setup();
quicksand 0:56230ba3cdeb 56 float vOut = sensor.Sense();
quicksand 0:56230ba3cdeb 57 pc.printf("\n\rMCP9700 reading: Vout: %.2f mV\n\r", vOut);
quicksand 0:56230ba3cdeb 58 LED_0 = 1;
quicksand 0:56230ba3cdeb 59 LED_1 = 1;
quicksand 0:56230ba3cdeb 60 LED_2 = 1;
quicksand 0:56230ba3cdeb 61 LED_3 = 1;
quicksand 0:56230ba3cdeb 62 hartbeat.attach(&beat, 1);
quicksand 0:56230ba3cdeb 63 SW2.fall(&sw1interrupt);
quicksand 0:56230ba3cdeb 64 SW1.fall(&sw2interrupt);
quicksand 0:56230ba3cdeb 65 while(!modem_command_check_ok("AT$GPS=1,16,0,65535,1,1\n")) pc.printf("Trying to start GPS...\r\n");
quicksand 0:56230ba3cdeb 66 pc.printf("GPS started!\r\n");
quicksand 0:56230ba3cdeb 67 while(1) {
quicksand 0:56230ba3cdeb 68 if(pc.readable()) {
quicksand 0:56230ba3cdeb 69 if (pc.getc() == 'a')
quicksand 0:56230ba3cdeb 70 modem_command_check_ok("AT$GSND\n");
quicksand 0:56230ba3cdeb 71 }
quicksand 0:56230ba3cdeb 72 int result = gps.sample();
quicksand 0:56230ba3cdeb 73 if(result != NO_LOCK) {
quicksand 0:56230ba3cdeb 74 if((result == RMC && gps.gprmc_status == 'A')) {
quicksand 0:56230ba3cdeb 75 if(txtimeout > updateinterval) {
quicksand 0:56230ba3cdeb 76 LED_3 = 0;
quicksand 0:56230ba3cdeb 77 hartbeat.detach();
quicksand 0:56230ba3cdeb 78 sensor.Sense();
quicksand 0:56230ba3cdeb 79 temperature = (signed char)rint(sensor.GetAverageTemp());
quicksand 0:56230ba3cdeb 80 pc.printf("\r\nGPRMC Fix: latitude: %f, longitude: %f Temperature: %d\r\n",gps.get_dec_latitude(),gps.get_dec_longitude(),temperature);
quicksand 0:56230ba3cdeb 81 char sfcommand[128];
quicksand 0:56230ba3cdeb 82 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!
quicksand 0:56230ba3cdeb 83 modem_command_check_ok(sfcommand);
quicksand 0:56230ba3cdeb 84 txtimeout = 0;
quicksand 0:56230ba3cdeb 85 LED_3 = 1;
quicksand 0:56230ba3cdeb 86 hartbeat.attach(&beat, 1);
quicksand 0:56230ba3cdeb 87 }
quicksand 0:56230ba3cdeb 88 } 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)
quicksand 0:56230ba3cdeb 89 LED_2 = 0;
quicksand 0:56230ba3cdeb 90 hartbeat.detach();
quicksand 0:56230ba3cdeb 91 sensor.Sense();
quicksand 0:56230ba3cdeb 92 temperature = (signed char)rint(sensor.GetAverageTemp());
quicksand 0:56230ba3cdeb 93 pc.printf("\r\nNo GPRMC Fix! (sending 0xffff... as position data) Temperature: %d\r\n",temperature);
quicksand 0:56230ba3cdeb 94 char sfcommand[128];
quicksand 0:56230ba3cdeb 95 sprintf(sfcommand, "AT$SF=%02x01010fffffffffffffffff,2,0\n", temperature & 0xff); // Remark & 0xff needed to limit the value to two bytes!
quicksand 0:56230ba3cdeb 96 modem_command_check_ok(sfcommand);
quicksand 0:56230ba3cdeb 97 txtimeout = 0;
quicksand 0:56230ba3cdeb 98 LED_2 = 1;
quicksand 0:56230ba3cdeb 99 hartbeat.attach(&beat, 1);
quicksand 0:56230ba3cdeb 100 }
quicksand 0:56230ba3cdeb 101 } 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)
quicksand 0:56230ba3cdeb 102 LED_2 = 0;
quicksand 0:56230ba3cdeb 103 hartbeat.detach();
quicksand 0:56230ba3cdeb 104 sensor.Sense();
quicksand 0:56230ba3cdeb 105 temperature = (signed char)rint(sensor.GetAverageTemp());
quicksand 0:56230ba3cdeb 106 pc.printf("\r\nNo GPRMC Fix! (sending 0xffff... as position data) Temperature: %d\r\n",temperature);
quicksand 0:56230ba3cdeb 107 char sfcommand[128];
quicksand 0:56230ba3cdeb 108 sprintf(sfcommand, "AT$SF=%02x01010fffffffffffffffff,2,0\n", temperature & 0xff); // Remark & 0xff needed to limit the value to two bytes!
quicksand 0:56230ba3cdeb 109 modem_command_check_ok(sfcommand);
quicksand 0:56230ba3cdeb 110 txtimeout = 0;
quicksand 0:56230ba3cdeb 111 LED_2 = 1;
quicksand 0:56230ba3cdeb 112 hartbeat.attach(&beat, 1);
quicksand 0:56230ba3cdeb 113 }
quicksand 0:56230ba3cdeb 114 }
quicksand 0:56230ba3cdeb 115 }
quicksand 0:56230ba3cdeb 116
quicksand 0:56230ba3cdeb 117 void modem_setup()
quicksand 0:56230ba3cdeb 118 {
quicksand 0:56230ba3cdeb 119 /* Reset to factory defaults */
quicksand 0:56230ba3cdeb 120 if(modem_command_check_ok("AT&F")) {
quicksand 0:56230ba3cdeb 121 pc.printf("Factory reset succesfull\r\n");
quicksand 0:56230ba3cdeb 122 } else {
quicksand 0:56230ba3cdeb 123 pc.printf("Factory reset TD120x failed\r\n");
quicksand 0:56230ba3cdeb 124 }
quicksand 0:56230ba3cdeb 125 /* Disable local echo */
quicksand 0:56230ba3cdeb 126 modem.printf("ATE0\n");
quicksand 0:56230ba3cdeb 127 if(modem_command_check_ok("ATE0")) {
quicksand 0:56230ba3cdeb 128 pc.printf("Local echo disabled\r\n");
quicksand 0:56230ba3cdeb 129 }
quicksand 0:56230ba3cdeb 130 /* Write to mem */
quicksand 0:56230ba3cdeb 131 if(modem_command_check_ok("AT&W")) {
quicksand 0:56230ba3cdeb 132 pc.printf("Settings saved!\r\n");
quicksand 0:56230ba3cdeb 133 }
quicksand 0:56230ba3cdeb 134 }
quicksand 0:56230ba3cdeb 135
quicksand 0:56230ba3cdeb 136 /* ISR for serial timeout */
quicksand 0:56230ba3cdeb 137 void sertmout()
quicksand 0:56230ba3cdeb 138 {
quicksand 0:56230ba3cdeb 139 ser_timeout = true;
quicksand 0:56230ba3cdeb 140 }
quicksand 0:56230ba3cdeb 141
quicksand 0:56230ba3cdeb 142 bool modem_command_check_ok(char * command)
quicksand 0:56230ba3cdeb 143 {
quicksand 0:56230ba3cdeb 144 /* first clear serial data buffers */
quicksand 0:56230ba3cdeb 145 while(modem.readable()) modem.getc();
quicksand 0:56230ba3cdeb 146 /* Timeout for response of the modem */
quicksand 0:56230ba3cdeb 147 Timeout tmout;
quicksand 0:56230ba3cdeb 148 ser_timeout = false;
quicksand 0:56230ba3cdeb 149 /* Buffer for incoming data */
quicksand 0:56230ba3cdeb 150 char responsebuffer[6];
quicksand 0:56230ba3cdeb 151 /* Flag to set when we get 'OK' response */
quicksand 0:56230ba3cdeb 152 bool ok = false;
quicksand 0:56230ba3cdeb 153 bool error = false;
quicksand 0:56230ba3cdeb 154 /* Print command to TD120x */
quicksand 0:56230ba3cdeb 155 modem.printf(command);
quicksand 0:56230ba3cdeb 156 /* Newline to activate command */
quicksand 0:56230ba3cdeb 157 modem.printf("\n");
quicksand 0:56230ba3cdeb 158 /* Wait untill serial feedback, max 3 seconds before timeout */
quicksand 0:56230ba3cdeb 159 tmout.attach(&sertmout, 3.0);
quicksand 0:56230ba3cdeb 160 while(!modem.readable()&& ser_timeout == false);
quicksand 0:56230ba3cdeb 161 while(!ok && !ser_timeout && !error) {
quicksand 0:56230ba3cdeb 162 if(modem.readable()) {
quicksand 0:56230ba3cdeb 163 for(int i = 0; i < 5; i++) {
quicksand 0:56230ba3cdeb 164 responsebuffer[i] = responsebuffer[i+1];
quicksand 0:56230ba3cdeb 165 }
quicksand 0:56230ba3cdeb 166 responsebuffer[5] = modem.getc();
quicksand 0:56230ba3cdeb 167 if(responsebuffer[0] == '\r' && responsebuffer[1] == '\n' && responsebuffer[2] == 'O' && responsebuffer[3] == 'K' && responsebuffer[4] == '\r' && responsebuffer[5] == '\n' ) {
quicksand 0:56230ba3cdeb 168 ok = true;
quicksand 0:56230ba3cdeb 169 } else if(responsebuffer[0] == '\r' && responsebuffer[1] == '\n' && responsebuffer[2] == 'E' && responsebuffer[3] == 'R' && responsebuffer[4] == 'R' && responsebuffer[5] == 'O' ) {
quicksand 0:56230ba3cdeb 170 error = true;
quicksand 0:56230ba3cdeb 171 }
quicksand 0:56230ba3cdeb 172 }
quicksand 0:56230ba3cdeb 173 }
quicksand 0:56230ba3cdeb 174 tmout.detach();
quicksand 0:56230ba3cdeb 175 return ok;
quicksand 0:56230ba3cdeb 176 }