-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathneo_m8_gps.c
312 lines (270 loc) · 7.18 KB
/
neo_m8_gps.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
* neo_m8_gps.c
*
* Created on: Jul 17, 2018
* Author: alexis
*/
#include "ringbuffer_char.h"
#include "neo_m8_gps.h"
#include "usart.h"
#include "string.h"
#include "neo_m8_messages.h"
#include "neo_m8_ubx_checksum.h"
/* Variables */
/* Ring buffer to store incoming bytes ; raw data storage */
static ring_buffer_t gps_rx_ring_buffer;
static char UBXPayload[128];
static UBXHeader header;
static char CRC_A;
static char CRC_B;
static UBXMsg ValidUBXMsg;
//todo: remove
static char gps_raw_buffer[200]; /* Buffer used to extract msg from ring buffer */
static char dbg_buf[128];
/* Initialisation function */
void neoInit(void)
{
/* Init the reception buffer */
neoInitRxBuf();
/* Enable interrupts */
//todo: use a define for the USART name and handler
HAL_NVIC_SetPriority(USART6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART6_IRQn);
/* Enable RX Not Empty interrupt */
__HAL_UART_ENABLE_IT(&huart6, UART_IT_RXNE);
}
void neoInitRxBuf(void)
{
ring_buffer_init(&gps_rx_ring_buffer);
}
uint32_t neoNumElemBuf(void)
{
return (uint32_t) ring_buffer_num_items(&gps_rx_ring_buffer);
}
/* Rx callback to handle the reception of one byte */
void neoRxCallback(char c)
{
#if 0 //todo: remove
uint32_t s;
s = snprintf(dbg_buf, 128, "rxd:%0x\n", c);
HAL_UART_Transmit(&huart3, dbg_buf, s, 0xff);
#endif
// Queue in ring buffer the rx'd byte
ring_buffer_queue(&gps_rx_ring_buffer, c);
//todo: fill ring buffer
}
void USART6_IRQHandler(void)
{
/* USER CODE BEGIN USART6_IRQn 0 */
if (__HAL_UART_GET_FLAG(&huart6, UART_FLAG_RXNE))
{
/*Clear the interrupt by reading the DR:*/
char rxdByte;
rxdByte = huart6.Instance->DR;
neoRxCallback(rxdByte);
}
/* USER CODE END USART6_IRQn 0 */
HAL_UART_IRQHandler(&huart6);
/* USER CODE BEGIN USART6_IRQn 1 */
/* USER CODE END USART6_IRQn 1 */
}
UBX_OP_RESULT neoRetrieveMsg(void)
{
static UBX_NEO_M8_DECODE_STATE smState = UBX_LOOKING_FOR_SYNC;
switch (smState)
{
case UBX_LOOKING_FOR_SYNC:
{
if (neoFindSyncBytes())
{
smState = UBX_BUILDING_MSG_INFOS;
/* Flow through */
}
else
{
return UBX_NO_DATA;
break;
}
}
case UBX_BUILDING_MSG_INFOS:
{
if (neoBuildHeader(&header))
{
/* Retrieved a header (informations of the UBX Packet: ID, Class, Len) */
/* Check the length, in case a error a very high value can be reached */
if (header.length > 172) //todo: define the max length of a ubx payload
{
/* That's too high, switch to previous state again */
smState = UBX_LOOKING_FOR_SYNC;
break;
}
else
{
/* Valide length, allow flow through the next state */
smState = UBX_CHECKING_CRC;
}
}
else
{
break;
}
}
case UBX_CHECKING_CRC:
{
int i;
char rxd_crca, rxd_crcb;
/* Check if enough data is present inside the buffer for this operation */
/* Header (4 bytes) + Payload (length bytes) + CRC (2 bytes) = length + 6 */
/* Last two bytes are the CRC, we won't copy it into the raw buffer, but in separate values */
if (ring_buffer_num_items(&gps_rx_ring_buffer) >= (header.length+6))
{
if (!neoCopyPacketFromRing(gps_raw_buffer, header.length+4))
{
/* Error to handle */
break;
}
/* Arrive here only if copy was successfull and CRC is available in ring buffer */
/* Verify checksum is correct */
/* Retrieve Rxd CRC*/
ring_buffer_peek(&gps_rx_ring_buffer, &rxd_crca, (header.length+4));
ring_buffer_peek(&gps_rx_ring_buffer, &rxd_crcb, (header.length+5));
/* Calculate CRC on Header (class + id + length) + payload */
UBX_Fletcher(gps_raw_buffer, header.length+4, &CRC_A, &CRC_B);
/* In any case, this is the end and it will be time to look for new SYNC bytes */
smState = UBX_LOOKING_FOR_SYNC;
/* Check CRC */
if ((CRC_A == rxd_crca) && (CRC_B == rxd_crcb))
{
/* We retrieved a correct message, remove it from ring buffer */
neoDequeueFromRing(header.length+6);
memset(ValidUBXMsg.payload, 0, 172);
memcpy(ValidUBXMsg.payload, &gps_raw_buffer[4], header.length);
ValidUBXMsg.header = header;
return UBX_NEW_DATA;
}
else
{
/* Else don't remove it and try to find a SYNC
* A packet could be present in the byte we dealt with, that's why we only peek'd */
return UBX_INCORRECT_PACKET_RXD;
}
}
else
{
/* Not enough item in the ring buffer, let him get feed */
return UBX_WAITING_MORE_DATA;
break;
}
/* Should never get there */
break;
}
}
}
/* Browse into the RX Ring buffer to find SYNC Char 1 followed by SYNC Char 2, indicating the begin of a UBX msg */
/* Returns true if we retrieved this combination, false otherwise */
bool neoFindSyncBytes()
{
char c1, c2;
while (!ring_buffer_is_empty(&gps_rx_ring_buffer) && (ring_buffer_num_items(&gps_rx_ring_buffer) >= 2))
{
ring_buffer_dequeue(&gps_rx_ring_buffer, &c1);
if (c1 == UBX_SYNC_CHAR1)
{
ring_buffer_peek(&gps_rx_ring_buffer, &c2, 0);
if (c2 == UBX_SYNC_CHAR2)
{
ring_buffer_dequeue(&gps_rx_ring_buffer, &c2); /* Dequeue the byte we just peek'd before */
return true; /* We just found SYNC1 followed by SYNC2 */
}
}
}
return false;
}
bool neoRetrieveHeaderBytes(char* buf)
{
int i;
for (i = 0; i < 4; i++)
{
if (!ring_buffer_peek(&gps_rx_ring_buffer, buf++, i))
{
/* The ring_buffer_peek will return false if the index don't exist
* it means that there are less than 4 bytes! */
return false;
}
}
/* Correctly peeked 4 bytes from the ring buffer */
return true;
}
bool neoBuildHeader(UBXHeader* header)
{
//memset(header->rawBuf, 0, 4);
if (neoRetrieveHeaderBytes(gps_raw_buffer))
{
/* Successfully retrieved 4 bytes to build a header */
header->class = gps_raw_buffer[0];
header->id = gps_raw_buffer[1];
header->length = gps_raw_buffer[3] << 8 | gps_raw_buffer[2]; /* Little Endian */
return true;
}
else
{
return false;
}
}
bool neoDequeueFromRing(uint32_t n)
{
char dummy;
if (ring_buffer_num_items(&gps_rx_ring_buffer) >= n)
{
//dequeue
for (int i = 0; i > n; i++)
{
ring_buffer_dequeue(&gps_rx_ring_buffer, &dummy);
}
}
}
/* This function copies bytes from a ring buffer to the raw buffer.
* Second argument is a pointer to the raw buffer,
* Third argument is the number of bytes to copy
* Returns true if the copy occured correctly,
* Returns false if something went wrong (not enough elements in the ring buffer)
* Use this function after the sync byte were detected and dequeue'd like this:
*/
bool neoCopyPacketFromRing(char* rbuffer, uint32_t n)
{
char dummy;
int i;
if (ring_buffer_num_items(&gps_rx_ring_buffer) >= n)
{
for (i = 0; i < (header.length+4); i++)
{
if (!ring_buffer_peek(&gps_rx_ring_buffer,&gps_raw_buffer[i], i))
{
/* Oops, no item at the index we indicated */
return false;
}
}
}
else
{
return false;
}
/* OK */
return true;
}
uint8_t neoGetMsgClass()
{
return ValidUBXMsg.header.class;
}
uint8_t neoGetMsgId()
{
return ValidUBXMsg.header.id;
}
uint16_t neoGetPayloadSize()
{
return ValidUBXMsg.header.length;
}
void UBXUpdate_NAV_PVT(ubx_nav_pvt_msg_t * dest)
{
UBX_Parse_Raw_To_NAV_PVT(ValidUBXMsg.payload, ValidUBXMsg.header.length, dest);
}