Skip to content

Commit c07f8de

Browse files
committed
GPS - Refactor out GPSHardware
1 parent 8b33ba7 commit c07f8de

File tree

6 files changed

+331
-251
lines changed

6 files changed

+331
-251
lines changed

src/components/gps/controller.cpp

Lines changed: 21 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -16,220 +16,50 @@
1616
#include "controller.h"
1717

1818
/*!
19-
* @brief Constructor
19+
* @brief Constructor for GPSController.
2020
*/
21-
GPSController::GPSController() {
22-
_gps_model = new GPSModel();
23-
_iface_type = GPS_IFACE_NONE;
24-
_driver_type = GPS_DRV_NONE;
25-
}
21+
GPSController::GPSController() { _gps_model = new GPSModel(); }
2622

2723
/*!
28-
* @brief Destructor
24+
* @brief Destructor for GPSController.
2925
*/
3026
GPSController::~GPSController() {
3127
// Clean up model
3228
if (_gps_model) {
3329
delete _gps_model;
3430
_gps_model = nullptr;
3531
}
36-
37-
// Clean up GPS instance
38-
if (_ada_gps) {
39-
delete _ada_gps;
40-
_ada_gps = nullptr;
41-
}
4232
}
4333

4434
/*!
45-
* @brief Handles a GPSConfig message from the protobuf stream.
46-
* @param stream
47-
* Pointer to a pb_istream_t object.
48-
* @returns True if the message was handled successfully, False otherwise.
35+
* @brief Adds a GPS hardware instance to the controller.
36+
* @param serial Pointer to the HardwareSerial instance for GPS communication.
37+
* @param gps_config Pointer to the GPS configuration message.
38+
* @return True if the GPS was added successfully, false otherwise.
4939
*/
50-
bool GPSController::Handle_GPSConfig(wippersnapper_gps_GPSConfig *gps_config) {
51-
// Attempt to decode the GPSConfig message
52-
if (_driver_type == GPS_DRV_MTK) {
53-
WS_DEBUG_PRINTLN("[gps] Handling GPSConfig for MediaTek driver...");
54-
if (gps_config == nullptr) {
55-
WS_DEBUG_PRINTLN("[gps] ERROR: No GPSConfig message found!");
56-
return false;
57-
}
58-
// Iterate through the command sentences and send them to the GPS module
59-
// TODO: We may want to break this out into a generic function that supports
60-
// MTK, Ublox, etc...
61-
for (size_t i = 0; i < gps_config->commands_count; i++) {
62-
WS_DEBUG_PRINT("[gps] Sending command to MediaTek GPS: ");
63-
WS_DEBUG_PRINTLN(gps_config->commands[i]);
64-
// Send the command to the GPS module
65-
_hw_serial->flush(); // Flush the serial buffer before sending
66-
_ada_gps->sendCommand(gps_config->commands[i]);
67-
// and wait for the corresponding response from the GPS module
68-
char msg_resp[MAX_NEMA_SENTENCE_LEN];
69-
if (!BuildPmtkAck(gps_config->commands[i], msg_resp)) {
70-
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to build PMTK ACK response!");
71-
return false;
72-
}
73-
if (!_ada_gps->waitForSentence(msg_resp)) {
74-
WS_DEBUG_PRINT("[gps] ERROR: Failed to get response | cmd:");
75-
WS_DEBUG_PRINTLN(gps_config->commands[i]);
76-
return false;
77-
}
78-
}
79-
} else {
80-
WS_DEBUG_PRINTLN("[gps] ERROR: Unsupported GPS driver type!");
81-
return false;
82-
}
40+
bool GPSController::AddGPS(HardwareSerial *serial,
41+
wippersnapper_gps_GPSConfig *gps_config) {
42+
GPSHardware *gps_hw = new GPSHardware();
8343

84-
return true;
85-
}
86-
87-
/*!
88-
* @brief Sets a UART hardware interface for the GPS controller.
89-
* @param serial
90-
* Pointer to a HardwareSerial instance.
91-
* @returns True if the interface was set successfully, False otherwise.
92-
*/
93-
bool GPSController::SetInterface(HardwareSerial *serial) {
94-
if (serial == nullptr)
95-
return false;
96-
// Set the hardware serial interface
97-
_hw_serial = serial;
98-
_iface_type = GPS_IFACE_UART_HW;
99-
return true;
100-
}
101-
102-
/*!
103-
* @brief Attempts to initialize the GPS device based on the configured
104-
* interface type.
105-
* @returns True if the GPS device was initialized successfully, False
106-
* otherwise.
107-
*/
108-
bool GPSController::begin() {
109-
// Validate if the interface type is set
110-
if (_iface_type == GPS_IFACE_NONE) {
111-
WS_DEBUG_PRINTLN("[gps] ERROR: No interface type configured!");
44+
if (!gps_hw->SetInterface(serial)) {
45+
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to set GPS interface!");
46+
delete gps_hw;
11247
return false;
11348
}
11449

115-
// Attempt to set the GPS interface type based on the hardware
116-
if (!QueryModuleType()) {
117-
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to query GPS module type!");
50+
if (!gps_hw->begin()) {
51+
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to initialize GPS hardware!");
52+
delete gps_hw;
11853
return false;
11954
}
12055

121-
WS_DEBUG_PRINTLN(
122-
"[gps] GPS module type detected successfully and ready for commands!");
123-
return true;
124-
}
125-
126-
/*!
127-
* @brief Queries the GPS driver type by attempting to detect MediaTek or u-blox
128-
* GPS modules.
129-
* @returns True if the driver type was detected successfully, False otherwise.
130-
*/
131-
bool GPSController::QueryModuleType() {
132-
// Validate if the interface is set
133-
if (_iface_type == GPS_IFACE_NONE) {
134-
WS_DEBUG_PRINTLN("[gps] ERROR: No interface configured for GPS!");
56+
if (!gps_hw->Handle_GPSConfig(gps_config)) {
57+
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to configure GPS!");
58+
delete gps_hw;
13559
return false;
13660
}
137-
WS_DEBUG_PRINTLN("[gps] Attempting to detect GPS module type...");
138-
139-
// Try to detect MediaTek GPS module
140-
if (DetectMediatek()) {
141-
WS_DEBUG_PRINTLN("[gps] Using MediaTek GPS driver!");
142-
return true;
143-
}
144-
145-
WS_DEBUG_PRINTLN("[gps] Failed to detect MTK GPS, attempting to detect "
146-
"u-blox GPS module...");
147-
// TODO: Implement u-blox detection here
148-
// if (DetectUblox()) {
149-
// return true;
150-
// }
151-
152-
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to detect GPS driver type, attempting "
153-
"to use generic driver!");
154-
// TODO: Implement generic NMEA GPS driver detection
15561

156-
// No responses from the GPS module over the defined iface, so we bail out
157-
WS_DEBUG_PRINTLN("[gps] ERROR: No GPS driver type detected!");
158-
return false;
159-
}
160-
161-
/*!
162-
* @brief Detects if the GPS module is a MediaTek GPS module by querying its
163-
* firmware version.
164-
* @returns True if a MediaTek GPS module was detected, False otherwise.
165-
*/
166-
bool GPSController::DetectMediatek() {
167-
if (_iface_type != GPS_IFACE_UART_HW) {
168-
WS_DEBUG_PRINTLN("[gps] ERROR: MediaTek GPS module only supports Hardware "
169-
"Serial interface!");
170-
return false;
171-
}
172-
173-
// Query MediaTek firmware version
174-
_hw_serial->flush();
175-
_hw_serial->println(CMD_MTK_QUERY_FW);
176-
// Wait for response
177-
uint16_t timeout = 2000; // 1 second timeout
178-
while (_hw_serial->available() < MAX_NEMA_SENTENCE_LEN && timeout--) {
179-
delay(1);
180-
}
181-
182-
if (timeout == 0)
183-
return false;
184-
185-
// We found a response, let's verify that it's the expected PMTK_DK_RELEASE
186-
// command by reading out the NMEA sentence string into a buffer
187-
size_t buf_len = MAX_NEMA_SENTENCE_LEN * 4; // +3 for \r\n and null terminator
188-
char buffer[buf_len];
189-
size_t available = _hw_serial->available();
190-
size_t bytes_to_read = min(available, buf_len - 1);
191-
// Print the two out
192-
WS_DEBUG_PRINT("[gps] Reading MediaTek GPS response: ");
193-
WS_DEBUG_PRINT(available);
194-
WS_DEBUG_PRINT(" bytes, reading ");
195-
WS_DEBUG_PRINTLN(bytes_to_read);
196-
for (size_t i = 0; i < bytes_to_read; i++) {
197-
buffer[i] = _hw_serial->read();
198-
}
199-
buffer[bytes_to_read] = '\0';
200-
WS_DEBUG_PRINT("[gps] MediaTek GPS response: ");
201-
WS_DEBUG_PRINTLN(buffer);
202-
// did we get the expected PMTK705 string?
203-
if (strncmp(buffer, CMD_MTK_QUERY_FW_RESP, 8) != 0) {
204-
return false;
205-
}
206-
207-
// Attempt to use Adafruit_GPS
208-
if (_ada_gps != nullptr) {
209-
delete _ada_gps; // Clean up previous instance if it exists
210-
}
211-
_ada_gps = new Adafruit_GPS(_hw_serial);
212-
if (!_ada_gps->begin(_hw_serial->baudRate())) {
213-
WS_DEBUG_PRINTLN("[gps] ERROR: Failed to initialize Mediatek!");
214-
return false;
215-
}
216-
_driver_type = GPS_DRV_MTK;
217-
return true;
218-
}
219-
220-
/*!
221-
* @brief Builds a PMTK acknowledgment message for the provided command.
222-
* @param msg_cmd
223-
* Pointer to a command string.
224-
* @param msg_resp
225-
* Pointer to a response string.
226-
* @returns True if the acknowledgment was built successfully, False otherwise.
227-
*/
228-
bool GPSController::BuildPmtkAck(char *msg_cmd, char *msg_resp) {
229-
int cmd_num = 0;
230-
if (sscanf(msg_cmd, "$PMTK%d", &cmd_num) != 1)
231-
return false;
232-
snprintf(msg_resp, MAX_NEMA_SENTENCE_LEN, "$PMTK001,%d,3", cmd_num);
233-
_ada_gps->addChecksum(msg_resp);
62+
_gps_hardware.push_back(gps_hw);
63+
WS_DEBUG_PRINTLN("[gps] GPS hardware added successfully!");
23464
return true;
23565
}

src/components/gps/controller.h

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,13 @@
1616
#ifndef WS_GPS_CONTROLLER_H
1717
#define WS_GPS_CONTROLLER_H
1818
#include "Wippersnapper_V2.h"
19+
#include "hardware.h"
1920
#include "model.h"
2021
#include <Adafruit_GPS.h>
2122

22-
#define CMD_MTK_QUERY_FW \
23-
"$PMTK605*31" ///< Request to query MediaTek firmware version
24-
#define CMD_MTK_QUERY_FW_RESP \
25-
"$PMTK705" ///< Response from querying MediaTek firmware version without the
26-
///< ReleaseStr
27-
#define MAX_NEMA_SENTENCE_LEN 82 ///< Maximum length of a NMEA sentence
28-
2923
class Wippersnapper_V2; ///< Forward declaration
3024
class GPSModel; ///< Forward declaration
31-
class UARTHardware; ///< Forward declaration
32-
33-
enum GpsInterfaceType {
34-
GPS_IFACE_NONE, ///< No interface/undefined
35-
GPS_IFACE_UART_HW, ///< UART hardware interface
36-
GPS_IFACE_UART_SW, ///< UART software interface
37-
GPS_IFACE_I2C ///< I2C interface
38-
}; ///< Type of interface used by GPS
39-
40-
enum GpsDriverType {
41-
GPS_DRV_NONE, ///< No driver/undefined
42-
GPS_DRV_MTK, ///< MediaTek GPS driver
43-
GPS_DRV_UBLOX, ///< u-blox GPS driver
44-
GPS_DRV_GENERIC_NMEA ///< Generic NMEA GPS driver
45-
}; ///< Type of GPS driver used
25+
class GPSHardware; ///< Forward declaration
4626

4727
/*!
4828
@brief Routes messages between the GPS.proto API and the hardware.
@@ -51,21 +31,12 @@ class GPSController {
5131
public:
5232
GPSController();
5333
~GPSController();
54-
bool SetInterface(HardwareSerial *serial);
55-
// TODO: Add SetInterface(I2C *_i2c_hardware) for I2C support here!
56-
bool begin();
57-
bool QueryModuleType();
58-
bool DetectMediatek();
59-
bool BuildPmtkAck(char *msg_cmd, char *msg_resp);
60-
// Protobuf API methods
61-
bool Handle_GPSConfig(wippersnapper_gps_GPSConfig *gps_config);
34+
bool AddGPS(HardwareSerial *serial, wippersnapper_gps_GPSConfig *gps_config);
6235

6336
private:
64-
GPSModel *_gps_model; ///< GPS model
65-
GpsInterfaceType _iface_type; ///< Type of interface used by GPS
66-
GpsDriverType _driver_type; ///< Type of GPS driver used
67-
HardwareSerial *_hw_serial = nullptr; ///< HardwareSerial instance for GPS;
68-
Adafruit_GPS *_ada_gps = nullptr; ///< Adafruit GPS instance
37+
GPSModel *_gps_model; ///< GPS model instance
38+
std::vector<GPSHardware *>
39+
_gps_hardware; ///< Vector of GPS hardware instances
6940
};
7041
extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance
7142
#endif // WS_GPS_CONTROLLER_H

0 commit comments

Comments
 (0)