Skip to content

Commit 9a9c57b

Browse files
committed
GPS - Refactor update() to remove funcs that should be called by the driver, make it less reliant on iface type and driver type, handle that all in hardware
1 parent d3afe8a commit 9a9c57b

File tree

4 files changed

+133
-93
lines changed

4 files changed

+133
-93
lines changed

src/components/gps/controller.cpp

Lines changed: 5 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -106,54 +106,6 @@ bool GPSController::AddGPS(HardwareSerial *serial,
106106
return true;
107107
}
108108

109-
/*!
110-
* @brief Pushes a new NMEA sentence into the circular buffer.
111-
* @param new_sentence Pointer to the new NMEA sentence to be added.
112-
* @return 0 on success, -1 if the buffer is full.
113-
*/
114-
int GPSController::NmeaBufPush(const char *new_sentence) {
115-
if (!new_sentence)
116-
return -1;
117-
118-
int next = _nmea_buff.head + 1; // points to head after the current write
119-
if (next >= _nmea_buff.maxlen)
120-
next = 0; // wrap around
121-
122-
// If buffer is full, advance tail to overwrite oldest data
123-
if (next == _nmea_buff.tail) {
124-
_nmea_buff.tail = (_nmea_buff.tail + 1) % _nmea_buff.maxlen;
125-
}
126-
127-
// Copy the new sentence into the buffer
128-
strncpy(_nmea_buff.sentences[_nmea_buff.head], new_sentence,
129-
MAX_LEN_NMEA_SENTENCE - 1);
130-
_nmea_buff.sentences[_nmea_buff.head][MAX_LEN_NMEA_SENTENCE - 1] = '\0';
131-
_nmea_buff.head = next;
132-
return 0;
133-
}
134-
135-
/*!
136-
* @brief Pops a NMEA sentence from the circular buffer, FIFO order.
137-
* @param sentence Pointer to the buffer where the popped sentence will be
138-
* stored.
139-
* @return 0 on success, -1 if the buffer is empty.
140-
*/
141-
int GPSController::NmeaBufPop(char *sentence) {
142-
// Is the buffer empty?
143-
if (_nmea_buff.head == _nmea_buff.tail)
144-
return -1;
145-
146-
int next =
147-
_nmea_buff.tail + 1; // next is where tail will point to after this read.
148-
if (next >= _nmea_buff.maxlen)
149-
next = 0;
150-
151-
// Copy sentence from tail
152-
strcpy(sentence, _nmea_buff.sentences[_nmea_buff.tail]);
153-
_nmea_buff.tail = next; // Advance tail
154-
return 0;
155-
}
156-
157109
/*!
158110
* @brief Updates the GPSController, polling the GPS hardware for data.
159111
* This function checks if the read period has elapsed and processes the GPS
@@ -203,41 +155,17 @@ void GPSController::update() {
203155
continue; // Not yet elapsed, skip this driver
204156

205157
// Discard the GPS buffer before we attempt to do a fresh read
206-
if (drv->GetIfaceType() == GPS_IFACE_UART_HW) {
207-
// TODO: Refactor this into a function within hardware.cpp
208-
size_t bytes_avail = ada_gps->available();
209-
if (bytes_avail > 0) {
210-
for (size_t i = 0; i < bytes_avail; i++) {
211-
ada_gps->read();
212-
}
213-
}
214-
} else if (drv->GetIfaceType() == GPS_IFACE_I2C) {
215-
drv->I2cReadDiscard();
216-
}
217-
218-
// Unset the RX flag
219-
if (ada_gps->newNMEAreceived()) {
220-
ada_gps->lastNMEA();
221-
}
158+
drv->ReadDiscardBuffer();
222159

223-
// Read from the GPS module for update_rate milliseconds
224-
ulong update_rate = 1000 / drv->GetNmeaUpdateRate();
225-
ulong start_time = millis();
226-
while (millis() - start_time < update_rate) {
227-
char c = ada_gps->read();
228-
// Check if we have a new NMEA sentence
229-
if (ada_gps->newNMEAreceived()) {
230-
// If we have a new sentence, push it to the buffer
231-
char *last_nmea = ada_gps->lastNMEA();
232-
NmeaBufPush(ada_gps->lastNMEA());
233-
}
234-
}
160+
// Poll the GPS hardware for update_rate ms
161+
// and store NMEA sentences in a ring buffer
162+
drv->PollStoreSentences();
235163

236164
// Parse each NMEA sentence in the buffer
237165
_gps_model->CreateGPSEvent();
238166
char nmea_sentence[MAX_LEN_NMEA_SENTENCE];
239167
bool has_gps_event = false;
240-
while (NmeaBufPop(nmea_sentence) != -1) {
168+
while (drv->NmeaBufPop(nmea_sentence) != -1) {
241169
// Parse the NMEA sentence
242170
WS_DEBUG_PRINT("[gps] Parsing NMEA sentence: ");
243171
WS_DEBUG_PRINTLN(nmea_sentence);

src/components/gps/controller.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@
2020
#include "model.h"
2121
#include <Adafruit_GPS.h>
2222

23-
#define MAX_NMEA_SENTENCES 10 ///< Size of the NMEA buffer
24-
#define MAX_LEN_NMEA_SENTENCE 82 ///< Maximum length of a NMEA sentence
25-
26-
typedef struct {
27-
char sentences[MAX_NMEA_SENTENCES][MAX_LEN_NMEA_SENTENCE];
28-
int head;
29-
int tail;
30-
int maxlen;
31-
} nmea_buffer_t;
32-
3323
class Wippersnapper_V2; ///< Forward declaration
3424
class GPSModel; ///< Forward declaration
3525
class GPSHardware; ///< Forward declaration
@@ -47,11 +37,8 @@ class GPSController {
4737
void update();
4838

4939
private:
50-
int NmeaBufPush(const char *new_sentence);
51-
int NmeaBufPop(char *sentence);
5240
GPSModel *_gps_model; ///< GPS model instance
5341
std::vector<GPSHardware *> _gps_drivers; ///< GPS hardware instances
54-
nmea_buffer_t _nmea_buff; ///< NMEA buffer for storing sentences
5542
};
5643
extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance
5744
#endif // WS_GPS_CONTROLLER_H

src/components/gps/hardware.cpp

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,4 +505,109 @@ GpsDriverType GPSHardware::GetDriverType() { return _driver_type; }
505505
* @brief Returns the interface type of the GPS hardware.
506506
* @returns The interface type of the GPS hardware.
507507
*/
508-
GpsInterfaceType GPSHardware::GetIfaceType() { return _iface_type; }
508+
GpsInterfaceType GPSHardware::GetIfaceType() { return _iface_type; }
509+
510+
/*!
511+
* @brief Discards any data in the UART RX buffer.
512+
*/
513+
void GPSHardware::UartReadDiscard() {
514+
if (_driver_type == GPS_DRV_MTK) {
515+
size_t bytes_avail = _ada_gps->available();
516+
if (bytes_avail > 0) {
517+
for (size_t i = 0; i < bytes_avail; i++) {
518+
_ada_gps->read();
519+
}
520+
}
521+
}
522+
// TODO: Support UBX's UART iface here
523+
}
524+
525+
/*!
526+
* @brief Discards any data in the UART or I2C RX buffer.
527+
*/
528+
void GPSHardware::ReadDiscardBuffer() {
529+
if (_iface_type == GPS_IFACE_UART_HW) {
530+
UartReadDiscard();
531+
} else if (_iface_type == GPS_IFACE_I2C) {
532+
I2cReadDiscard();
533+
} else {
534+
WS_DEBUG_PRINTLN("[gps] ERROR: Unsupported GPS interface type!");
535+
}
536+
}
537+
538+
/*!
539+
* @brief Polls the GPS hardware for new NMEA sentences and stores them in a
540+
* circular buffer.
541+
*/
542+
void GPSHardware::PollStoreSentences() {
543+
if (_driver_type == GPS_DRV_MTK) {
544+
// Before we poll, Unset the RX flag
545+
if (_ada_gps->newNMEAreceived())
546+
_ada_gps->lastNMEA();
547+
548+
// Read from the GPS module for update_rate milliseconds
549+
ulong update_rate = 1000 / _nmea_update_rate;
550+
ulong start_time = millis();
551+
while (millis() - start_time < update_rate) {
552+
char c = _ada_gps->read();
553+
// Check if we have a new NMEA sentence
554+
if (_ada_gps->newNMEAreceived()) {
555+
// If we have a new sentence, push it to the buffer
556+
char *last_nmea = _ada_gps->lastNMEA();
557+
NmeaBufPush(_ada_gps->lastNMEA());
558+
}
559+
}
560+
} else if (_driver_type == GPS_DRV_UBLOX) {
561+
// TODO!
562+
} else {
563+
WS_DEBUG_PRINTLN("[gps] ERROR: Unsupported GPS driver type for polling!");
564+
}
565+
}
566+
567+
/*!
568+
* @brief Pushes a new NMEA sentence into the circular buffer.
569+
* @param new_sentence Pointer to the new NMEA sentence to be added.
570+
* @return 0 on success, -1 if the buffer is full.
571+
*/
572+
int GPSHardware::NmeaBufPush(const char *new_sentence) {
573+
if (!new_sentence)
574+
return -1;
575+
576+
int next = _nmea_buff.head + 1; // points to head after the current write
577+
if (next >= _nmea_buff.maxlen)
578+
next = 0; // wrap around
579+
580+
// If buffer is full, advance tail to overwrite oldest data
581+
if (next == _nmea_buff.tail) {
582+
_nmea_buff.tail = (_nmea_buff.tail + 1) % _nmea_buff.maxlen;
583+
}
584+
585+
// Copy the new sentence into the buffer
586+
strncpy(_nmea_buff.sentences[_nmea_buff.head], new_sentence,
587+
MAX_LEN_NMEA_SENTENCE - 1);
588+
_nmea_buff.sentences[_nmea_buff.head][MAX_LEN_NMEA_SENTENCE - 1] = '\0';
589+
_nmea_buff.head = next;
590+
return 0;
591+
}
592+
593+
/*!
594+
* @brief Pops a NMEA sentence from the circular buffer, FIFO order.
595+
* @param sentence Pointer to the buffer where the popped sentence will be
596+
* stored.
597+
* @return 0 on success, -1 if the buffer is empty.
598+
*/
599+
int GPSHardware::NmeaBufPop(char *sentence) {
600+
// Is the buffer empty?
601+
if (_nmea_buff.head == _nmea_buff.tail)
602+
return -1;
603+
604+
int next =
605+
_nmea_buff.tail + 1; // next is where tail will point to after this read.
606+
if (next >= _nmea_buff.maxlen)
607+
next = 0;
608+
609+
// Copy sentence from tail
610+
strcpy(sentence, _nmea_buff.sentences[_nmea_buff.tail]);
611+
_nmea_buff.tail = next; // Advance tail
612+
return 0;
613+
}

src/components/gps/hardware.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
#define DEFAULT_MTK_NMEA_BAUD_RATE 9600 ///< Default NMEA baud rate in bits per
3030
#define MAX_NEMA_SENTENCE_LEN 82 ///< Maximum length of a NMEA sentence
3131
#define PA1010D_I2C_ADDRESS 0x10 ///< I2C address for PA1010D GPS module
32-
#define UBX_I2C_ADDRESS 0x42 ///< I2C address for all u-Blox GPS products
32+
#define UBX_I2C_ADDRESS 0x42 ///< I2C address for all u-Blox GPS products
33+
#define MAX_NMEA_SENTENCES 10 ///< Size of the NMEA buffer
34+
#define MAX_LEN_NMEA_SENTENCE 82 ///< Maximum length of a NMEA sentence
3335

3436
class Wippersnapper_V2; ///< Forward declaration
3537
class UARTHardware; ///< Forward declaration
@@ -48,6 +50,13 @@ enum GpsDriverType {
4850
GPS_DRV_GENERIC_NMEA ///< Generic NMEA GPS driver
4951
}; ///< Type of GPS driver used
5052

53+
typedef struct {
54+
char sentences[MAX_NMEA_SENTENCES][MAX_LEN_NMEA_SENTENCE];
55+
int head;
56+
int tail;
57+
int maxlen;
58+
} nmea_buffer_t; ///< NMEA sentence ring buffer structure
59+
5160
/*!
5261
@brief Low-level hardware interface for WipperSnapper's generic GPS
5362
component. This class handles the communication with the GPS module
@@ -77,14 +86,20 @@ class GPSHardware {
7786
SFE_UBLOX_GNSS *GetUbxGps();
7887
GpsDriverType GetDriverType();
7988
GpsInterfaceType GetIfaceType();
80-
void I2cReadDiscard();
89+
// HAL Abstraction for GPS driver commands
90+
// Used to abstract the Adafruit_GPS and SFE_UBLOX_GNSS libraries
91+
// and intelligently handle the differences between them
92+
void ReadDiscardBuffer();
93+
void PollStoreSentences();
8194

8295
private:
8396
bool QueryModuleType();
8497
bool DetectMtkUart();
8598
bool DetectMtkI2C(uint32_t addr);
8699
bool DetectUbxI2C(uint32_t addr);
87100
bool BuildPmtkAck(char *msg_cmd, char *msg_resp);
101+
void I2cReadDiscard();
102+
void UartReadDiscard();
88103
GpsInterfaceType _iface_type; ///< Type of interface used by GPS
89104
GpsDriverType _driver_type; ///< Type of GPS driver used by GPS
90105
HardwareSerial *_hw_serial = nullptr; ///< Optional HardwareSerial instance
@@ -100,6 +115,11 @@ class GPSHardware {
100115
MicroNMEA
101116
*_micro_nmea; ///< Optional MicroNMEA instance for parsing NMEA sentences
102117
char _micro_nmea_buf[100]; ///< Optional Buffer for MicroNMEA parsing
118+
// NMEA sentence ring buffer
119+
int NmeaBufPush(
120+
const char *new_sentence); ///< Push a sentence to the NMEA buffer
121+
int NmeaBufPop(char *sentence); ///< Pop a sentence from the NMEA buffer
122+
nmea_buffer_t _nmea_buff; ///< NMEA buffer for storing sentences
103123
};
104124
extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance
105125
#endif // WS_GPS_HARDWARE_H

0 commit comments

Comments
 (0)