SELKIELogger  1.0.0
GPSMessages.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <math.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "GPSMessages.h"
29 
38 void ubx_calc_checksum(const ubx_message *msg, uint8_t *csA, uint8_t *csB) {
39  uint8_t a = 0;
40  uint8_t b = 0;
41  a += msg->msgClass;
42  b += a;
43  a += msg->msgID;
44  b += a;
45  a += (msg->length & 0xFF);
46  b += a;
47  a += (msg->length >> 8);
48  b += a;
49  if (msg->length <= 256) {
50  for (uint8_t dx = 0; dx < msg->length; dx++) {
51  a += msg->data[dx];
52  b += a;
53  }
54  } else {
55  for (uint16_t dx = 0; dx < msg->length; dx++) {
56  a += msg->extdata[dx];
57  b += a;
58  }
59  }
60  *csA = a;
61  *csB = b;
62  return;
63 }
64 
72  ubx_calc_checksum(msg, &(msg->csumA), &(msg->csumB));
73 }
74 
82 bool ubx_check_checksum(const ubx_message *msg) {
83  uint8_t a = 0;
84  uint8_t b = 0;
85  ubx_calc_checksum(msg, &a, &b);
86  if ((msg->csumA == a) && (msg->csumB == b)) { return true; }
87  return false;
88 }
89 
100 size_t ubx_flat_array(const ubx_message *msg, uint8_t **out) {
101  size_t asize = 8 + msg->length;
102  uint8_t *outarray = calloc(asize, 1);
103  size_t ix = 0;
104  outarray[ix++] = msg->sync1;
105  outarray[ix++] = msg->sync2;
106  outarray[ix++] = msg->msgClass;
107  outarray[ix++] = msg->msgID;
108  outarray[ix++] = (uint8_t)(msg->length & 0xFF);
109  outarray[ix++] = (uint8_t)(msg->length >> 8);
110 
111  if (msg->length <= 256) {
112  memcpy(outarray + ix, msg->data, msg->length);
113  ix += msg->length;
114  } else {
115  memcpy(outarray + ix, msg->extdata, msg->length);
116  ix += msg->length;
117  }
118  outarray[ix++] = msg->csumA;
119  outarray[ix++] = msg->csumB;
120 
121  (*out) = outarray;
122  return ix;
123 }
124 
134 char *ubx_string_hex(const ubx_message *msg) {
135  int strlength = 24 + 3 * msg->length;
136  char *str = calloc(strlength, 1);
137  sprintf(str, "%02x %02x %02x %02x ", msg->sync1, msg->sync2, msg->msgClass, msg->msgID);
138  sprintf(str + 12, "%02x %02x ", (uint8_t)(msg->length & 0xFF), (uint8_t)(msg->length >> 8));
139  if (msg->length <= 256) {
140  for (uint8_t ix = 0; ix < msg->length; ix++) {
141  sprintf(str + 18 + 3 * ix, "%02x ", msg->data[ix]);
142  }
143  } else {
144  for (uint16_t ix = 0; ix < msg->length; ix++) {
145  sprintf(str + 18 + 3 * ix, "%02x ", msg->extdata[ix]);
146  }
147  }
148  sprintf(str + 18 + 3 * msg->length, "%02x %02x", msg->csumA, msg->csumB);
149  return str;
150 }
151 
158 void ubx_print_hex(const ubx_message *msg) {
159  char *out = ubx_string_hex(msg);
160  if (out) {
161  printf("%s\n", out);
162  free(out);
163  out = NULL;
164  }
165 }
166 
176  if (out == NULL || msg == NULL) { return false; }
177 
178  if (msg->msgClass != UBXNAV || msg->msgID != 0x07) { return false; }
179 
180  const uint8_t *d = msg->data;
181  out->tow = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
182  out->year = d[4] + (d[5] << 8);
183  out->month = d[6];
184  out->day = d[7];
185  out->hour = d[8];
186  out->minute = d[9];
187  out->second = d[10];
188  out->validDate = d[11] & 0x01;
189  out->validTime = d[11] & 0x02;
190  out->validMagDec = d[11] & 0x08;
191  out->accuracy = d[12] + (d[13] << 8) + (d[14] << 16) + (d[15] << 24);
192  out->nanosecond = (int32_t)(d[16] + (d[17] << 8) + (d[18] << 16) + (d[19] << 24));
193  out->fixType = d[20];
194  out->fixFlags = d[21];
195  out->fixFlags2 = d[22];
196  out->numSV = d[23];
197  out->longitude = ((int32_t)(d[24] + (d[25] << 8) + (d[26] << 16) + (d[27] << 24))) * 1E-7;
198  out->latitude = ((int32_t)(d[28] + (d[29] << 8) + (d[30] << 16) + (d[31] << 24))) * 1E-7;
199  out->height = (int32_t)(d[32] + (d[33] << 8) + (d[34] << 16) + (d[35] << 24));
200  out->ASL = (int32_t)(d[36] + (d[37] << 8) + (d[38] << 16) + (d[39] << 24));
201  out->horizAcc = d[40] + (d[41] << 8) + (d[42] << 16) + (d[43] << 24);
202  out->vertAcc = d[44] + (d[45] << 8) + (d[46] << 16) + (d[47] << 24);
203  out->northV = (int32_t)(d[48] + (d[49] << 8) + (d[50] << 16) + (d[51] << 24));
204  out->eastV = (int32_t)(d[52] + (d[53] << 8) + (d[54] << 16) + (d[55] << 24));
205  out->downV = (int32_t)(d[56] + (d[57] << 8) + (d[58] << 16) + (d[59] << 24));
206  out->groundSpeed = (int32_t)(d[60] + (d[61] << 8) + (d[62] << 16) + (d[63] << 24));
207  out->heading = ((int32_t)(d[64] + (d[65] << 8) + (d[66] << 16) + (d[67] << 24))) * 1E-5;
208  out->speedAcc = (int32_t)(d[68] + (d[69] << 8) + (d[70] << 16) + (d[71] << 24));
209  out->headingAcc = ((int32_t)(d[72] + (d[73] << 8) + (d[74] << 16) + (d[75] << 24))) * 1E-5;
210  out->pDOP = d[76] + (d[77] << 8);
211  out->pvtFlags = d[78];
212  if (msg->length == 92) {
213  out->vehicleHeading = ((int32_t)(d[84] + (d[85] << 8) + (d[86] << 16) + (d[87] << 24))) * 1E-5;
214  out->magneticDeclination = ((int32_t)(d[88] + (d[89] << 8))) * 1E-2;
215  out->magDecAcc = ((int32_t)(d[90] + (d[91] << 8) + (d[92] << 16) + (d[93] << 24))) * 1E-2;
216  } else {
217  out->vehicleHeading = NAN;
218  out->magneticDeclination = NAN;
219  out->magDecAcc = NAN;
220  }
221  return true;
222 }
bool ubx_check_checksum(const ubx_message *msg)
Verify checksum bytes of UBX message.
Definition: GPSMessages.c:82
bool ubx_decode_nav_pvt(const ubx_message *msg, ubx_nav_pvt *out)
Decode UBX NAV-PVT message.
Definition: GPSMessages.c:175
void ubx_print_hex(const ubx_message *msg)
Print UBX message in hexadecimal form.
Definition: GPSMessages.c:158
void ubx_set_checksum(ubx_message *msg)
Set checksum bytes for UBX message.
Definition: GPSMessages.c:71
void ubx_calc_checksum(const ubx_message *msg, uint8_t *csA, uint8_t *csB)
Calculate checksum for UBX message.
Definition: GPSMessages.c:38
size_t ubx_flat_array(const ubx_message *msg, uint8_t **out)
Convert UBX message to flat array of bytes.
Definition: GPSMessages.c:100
char * ubx_string_hex(const ubx_message *msg)
Return UBX message as string of hexadecimal pairs.
Definition: GPSMessages.c:134
Internal representation of a UBX message.
Definition: GPSTypes.h:80
uint8_t csumB
Checksum part B.
Definition: GPSTypes.h:88
uint8_t * extdata
Definition: GPSTypes.h:89
uint8_t sync1
Should always be 0xB5.
Definition: GPSTypes.h:81
uint8_t sync2
Should always be 0x62.
Definition: GPSTypes.h:82
uint8_t data[256]
Data if length <= 256.
Definition: GPSTypes.h:86
uint8_t msgClass
A value from ubx_class.
Definition: GPSTypes.h:83
uint8_t msgID
Message ID byte.
Definition: GPSTypes.h:84
uint16_t length
Message length.
Definition: GPSTypes.h:85
uint8_t csumA
Checksum part A.
Definition: GPSTypes.h:87
Represent decoded NAV-PVT message.
Definition: GPSTypes.h:101
int32_t downV
Velocity (Down, mm/s)
Definition: GPSTypes.h:126
uint8_t second
Second (UTC)
Definition: GPSTypes.h:108
uint32_t tow
GPS Time of Week.
Definition: GPSTypes.h:102
uint8_t minute
Minute (UTC)
Definition: GPSTypes.h:107
uint8_t numSV
Number of satellites used for current solution.
Definition: GPSTypes.h:117
int32_t ASL
Height above mean sea level (?datum)
Definition: GPSTypes.h:121
uint32_t accuracy
Estimated time accuracy (ns)
Definition: GPSTypes.h:112
float magneticDeclination
Local magnetic field declination.
Definition: GPSTypes.h:134
float latitude
WGS84 Latitude.
Definition: GPSTypes.h:119
uint32_t vertAcc
Vertical accuracy estimate.
Definition: GPSTypes.h:123
int32_t headingAcc
Heading accuracy estimate.
Definition: GPSTypes.h:130
bool validTime
Time data valid.
Definition: GPSTypes.h:110
uint8_t fixType
Navigation Fix type.
Definition: GPSTypes.h:114
int32_t speedAcc
Speed/velocity accuracy estimate.
Definition: GPSTypes.h:129
uint16_t year
Calendar year.
Definition: GPSTypes.h:103
int32_t groundSpeed
Ground Speed (mm/s)
Definition: GPSTypes.h:127
int32_t northV
Velocity (North, mm/s)
Definition: GPSTypes.h:124
int32_t height
WGS84 Height.
Definition: GPSTypes.h:120
uint8_t pvtFlags
More flags.
Definition: GPSTypes.h:132
uint32_t horizAcc
Horizontal accuracy estimate (mm)
Definition: GPSTypes.h:122
bool validMagDec
Magnetic declination data valid.
Definition: GPSTypes.h:111
float heading
Motion heading.
Definition: GPSTypes.h:128
int32_t eastV
Velocity (East, mm/s)
Definition: GPSTypes.h:125
uint8_t fixFlags
Navigation status flags.
Definition: GPSTypes.h:115
uint16_t pDOP
Position dilution.
Definition: GPSTypes.h:131
uint8_t fixFlags2
Expanded navigation status flags.
Definition: GPSTypes.h:116
int32_t nanosecond
+/- nanosecond (UTC)
Definition: GPSTypes.h:113
uint8_t month
Calendar month.
Definition: GPSTypes.h:104
float magDecAcc
Estimated accuracty of magnetic field declination.
Definition: GPSTypes.h:135
float longitude
WGS84 Longitude.
Definition: GPSTypes.h:118
uint8_t day
Calendar day.
Definition: GPSTypes.h:105
uint8_t hour
Hour (UTC)
Definition: GPSTypes.h:106
float vehicleHeading
Vehicle orientation.
Definition: GPSTypes.h:133
bool validDate
Date data valid.
Definition: GPSTypes.h:109