1 #include <twr_sam_m8q.h>
5 static void _twr_sam_m8q_task(
void *param);
6 static bool _twr_sam_m8q_parse(
twr_sam_m8q_t *
self,
const char *line);
19 self->_i2c_channel = channel;
20 self->_i2c_address = i2c_address;
21 self->_driver = driver;
28 self->_event_handler = event_handler;
29 self->_event_param = event_param;
36 self->_running =
true;
37 self->_configured =
false;
47 self->_running =
false;
55 self->_rmc.valid =
false;
56 self->_gga.valid =
false;
57 self->_pubx.valid =
false;
62 memset(time, 0,
sizeof(*time));
64 if (!self->_rmc.valid)
69 time->
year =
self->_rmc.date.year + 2000;
70 time->
month =
self->_rmc.date.month;
71 time->
day =
self->_rmc.date.day;
72 time->
hours =
self->_rmc.time.hours;
73 time->
minutes =
self->_rmc.time.minutes;
74 time->
seconds =
self->_rmc.time.seconds;
81 memset(position, 0,
sizeof(*position));
83 if (!self->_rmc.valid)
88 position->
latitude =
self->_rmc.latitude;
89 position->
longitude =
self->_rmc.longitude;
96 memset(altitude, 0,
sizeof(*altitude));
98 if (!self->_gga.valid || self->_gga.fix_quality < 1)
103 altitude->
altitude =
self->_gga.altitude;
104 altitude->
units =
self->_gga.altitude_units;
111 memset(quality, 0,
sizeof(*quality));
113 if (!self->_gga.valid || !self->_pubx.valid)
126 memset(accuracy, 0,
sizeof(*accuracy));
128 if (!self->_pubx.valid || self->_gga.fix_quality < 1)
133 accuracy->
horizontal =
self->_pubx.h_accuracy;
134 accuracy->
vertical =
self->_pubx.v_accuracy;
139 static void _twr_sam_m8q_task(
void *param)
145 self->_state = TWR_SAM_M8Q_STATE_STOP;
148 if (self->_running && self->_state == TWR_SAM_M8Q_STATE_STOP)
150 self->_state = TWR_SAM_M8Q_STATE_START;
155 switch (self->_state)
157 case TWR_SAM_M8Q_STATE_ERROR:
159 if (self->_event_handler != NULL)
164 self->_state = TWR_SAM_M8Q_STATE_STOP;
168 case TWR_SAM_M8Q_STATE_START:
170 if (!_twr_sam_m8q_enable(
self))
172 self->_state = TWR_SAM_M8Q_STATE_ERROR;
177 _twr_sam_m8q_clear(
self);
179 if (self->_event_handler != NULL)
184 self->_state = TWR_SAM_M8Q_STATE_READ;
190 case TWR_SAM_M8Q_STATE_READ:
192 uint16_t bytes_available;
196 self->_state = TWR_SAM_M8Q_STATE_ERROR;
201 while (bytes_available != 0)
203 self->_ddc_length = bytes_available;
205 if (self->_ddc_length >
sizeof(self->_ddc_buffer))
207 self->_ddc_length =
sizeof(
self->_ddc_buffer);
210 memset(self->_ddc_buffer, 0,
sizeof(self->_ddc_buffer));
216 transfer.
buffer =
self->_ddc_buffer;
217 transfer.
length =
self->_ddc_length;
221 self->_state = TWR_SAM_M8Q_STATE_ERROR;
226 for (
size_t i = 0; i <
self->_ddc_length; i++)
228 if (_twr_sam_m8q_feed(
self, self->_ddc_buffer[i]))
230 self->_state = TWR_SAM_M8Q_STATE_UPDATE;
234 bytes_available -=
self->_ddc_length;
237 if (self->_state == TWR_SAM_M8Q_STATE_UPDATE)
246 case TWR_SAM_M8Q_STATE_UPDATE:
248 self->_state = TWR_SAM_M8Q_STATE_READ;
252 if (self->_event_handler != NULL)
259 case TWR_SAM_M8Q_STATE_STOP:
261 self->_running =
false;
263 if (!_twr_sam_m8q_disable(
self))
265 self->_state = TWR_SAM_M8Q_STATE_ERROR;
270 if (self->_event_handler != NULL)
279 self->_state = TWR_SAM_M8Q_STATE_ERROR;
286 static bool _twr_sam_m8q_parse(
twr_sam_m8q_t *
self,
const char *line)
290 enum minmea_sentence_id
id = minmea_sentence_id(line,
true);
292 if (
id == MINMEA_SENTENCE_RMC)
294 struct minmea_sentence_rmc frame;
296 if (minmea_parse_rmc(&frame, line))
300 self->_rmc.date.year = frame.date.year;
301 self->_rmc.date.month = frame.date.month;
302 self->_rmc.date.day = frame.date.day;
303 self->_rmc.time.hours = frame.time.hours;
304 self->_rmc.time.minutes = frame.time.minutes;
305 self->_rmc.time.seconds = frame.time.seconds;
306 self->_rmc.latitude = minmea_tocoord(&frame.latitude);
307 self->_rmc.longitude = minmea_tocoord(&frame.longitude);
308 self->_rmc.valid =
true;
314 else if (
id == MINMEA_SENTENCE_GGA)
316 struct minmea_sentence_gga frame;
318 if (minmea_parse_gga(&frame, line))
320 self->_gga.fix_quality = frame.fix_quality;
321 self->_gga.altitude = minmea_tofloat(&frame.altitude);
322 self->_gga.altitude_units = frame.altitude_units;
323 self->_gga.valid =
true;
328 else if (
id == MINMEA_SENTENCE_PUBX)
330 struct minmea_sentence_pubx frame;
332 if (minmea_parse_pubx(&frame, line))
334 self->_pubx.h_accuracy = minmea_tofloat(&frame.h_accuracy);
335 self->_pubx.v_accuracy = minmea_tofloat(&frame.v_accuracy);
336 self->_pubx.speed = minmea_tofloat(&frame.speed);
337 self->_pubx.course = minmea_tofloat(&frame.course);
338 self->_pubx.satellites = frame.satellites;
339 self->_pubx.valid =
true;
352 if (c ==
'\r' || c ==
'\n')
354 if (self->_line_length != 0)
356 if (!self->_line_clipped)
358 if (_twr_sam_m8q_parse(
self, self->_line_buffer))
364 _twr_sam_m8q_clear(
self);
366 if (!self->_configured)
368 if (_twr_sam_m8q_send_config(
self))
370 self->_configured =
true;
377 if (self->_line_length <
sizeof(self->_line_buffer) - 1)
379 self->_line_buffer[
self->_line_length++] = c;
383 self->_line_clipped =
true;
392 memset(self->_line_buffer, 0,
sizeof(self->_line_buffer));
394 self->_line_clipped =
false;
395 self->_line_length = 0;
400 if (self->_driver != NULL)
402 if (!self->_driver->on(
self))
413 if (self->_driver != NULL)
415 if (!self->_driver->off(
self))
427 uint8_t config_msg_pubx[] = {
428 0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xf1, 0x00,
429 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x04, 0x3b
434 transfer.
buffer = config_msg_pubx;
435 transfer.
length =
sizeof(config_msg_pubx);
443 uint8_t config_msg_gsa[] = {
444 0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xf0, 0x02,
445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31,
449 transfer.
buffer = config_msg_gsa;
450 transfer.
length =
sizeof(config_msg_gsa);
458 uint8_t config_msg_gsv[] = {
459 0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xf0, 0x03,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38,
464 transfer.
buffer = config_msg_gsv;
465 transfer.
length =
sizeof(config_msg_gsv);
473 uint8_t config_gnss[] = {
474 0xb5, 0x62, 0x06, 0x3e, 0x3c, 0x00, 0x00, 0x20,
475 0x20, 0x07, 0x00, 0x08, 0x10, 0x00, 0x01, 0x00,
476 0x01, 0x01, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00,
477 0x01, 0x01, 0x02, 0x04, 0x08, 0x00, 0x01, 0x00,
478 0x01, 0x01, 0x03, 0x08, 0x10, 0x00, 0x00, 0x00,
479 0x01, 0x01, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
480 0x01, 0x03, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00,
481 0x01, 0x05, 0x06, 0x08, 0x0e, 0x00, 0x01, 0x00,
482 0x01, 0x01, 0x55, 0x47,
486 transfer.
buffer = config_gnss;
487 transfer.
length =
sizeof(config_gnss);
495 uint8_t config_nmea[] = {
496 0xb5, 0x62, 0x06, 0x17, 0x14, 0x00, 0x00, 0x41,
497 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x00, 0x75, 0x57,
503 transfer.
buffer = config_nmea;
504 transfer.
length =
sizeof(config_nmea);
void twr_i2c_init(twr_i2c_channel_t channel, twr_i2c_speed_t speed)
Initialize I2C channel.
bool twr_i2c_memory_read(twr_i2c_channel_t channel, const twr_i2c_memory_transfer_t *transfer)
Memory read from I2C channel.
bool twr_i2c_memory_read_16b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t *data)
Memory read 2 bytes from I2C channel.
bool twr_i2c_write(twr_i2c_channel_t channel, const twr_i2c_transfer_t *transfer)
Write to I2C channel.
twr_i2c_channel_t
I2C channels.
@ TWR_I2C_SPEED_100_KHZ
I2C communication speed is 100 kHz.
@ TWR_I2C_I2C0
I2C channel I2C0.
void twr_sam_m8q_stop(twr_sam_m8q_t *self)
Stop navigation module.
void twr_sam_m8q_invalidate(twr_sam_m8q_t *self)
Invalidate navigation data.
void twr_sam_m8q_start(twr_sam_m8q_t *self)
Start navigation module.
float longitude
Longitude.
void twr_sam_m8q_init(twr_sam_m8q_t *self, twr_i2c_channel_t channel, uint8_t i2c_address, const twr_sam_m8q_driver_t *driver)
Initialize SAM-M8Q module driver.
void twr_sam_m8q_set_event_handler(twr_sam_m8q_t *self, twr_sam_m8q_event_handler_t event_handler, void *event_param)
Set callback function.
float horizontal
Horizontal accuracy estimate.
int satellites_tracked
Number of satellites tracked.
bool twr_sam_m8q_get_quality(twr_sam_m8q_t *self, twr_sam_m8q_quality_t *quality)
Get quality.
bool twr_sam_m8q_get_accuracy(twr_sam_m8q_t *self, twr_sam_m8q_accuracy_t *accuracy)
Get accuracy.
struct twr_sam_m8q_t twr_sam_m8q_t
SAM-M8Q instance.
float vertical
Vertical accuracy estimate.
bool twr_sam_m8q_get_time(twr_sam_m8q_t *self, twr_sam_m8q_time_t *time)
Get time.
bool twr_sam_m8q_get_position(twr_sam_m8q_t *self, twr_sam_m8q_position_t *position)
Get position.
int fix_quality
Fix quality.
char units
Units of altitude.
bool twr_sam_m8q_get_altitude(twr_sam_m8q_t *self, twr_sam_m8q_altitude_t *altitude)
Get altitude.
@ TWR_SAM_M8Q_EVENT_ERROR
Error event.
@ TWR_SAM_M8Q_EVENT_STOP
Stop event.
@ TWR_SAM_M8Q_EVENT_START
Start event.
@ TWR_SAM_M8Q_EVENT_UPDATE
Update event.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
#define TWR_TICK_INFINITY
Maximum timestamp value.
I2C memory transfer parameters.
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with TWR_I2C_MEMORY_ADDRESS_16...
uint8_t device_address
7-bit I2C device address
size_t length
Length of buffer which is being written or read.
void * buffer
Pointer to buffer which is being written or read.
void * buffer
Pointer to buffer which is being written or read.
uint8_t device_address
7-bit I2C device address
size_t length
Length of buffer which is being written or read.