Adafruit_uBlox/Adafruit_UBloxDDC.cpp
2025-07-21 11:55:56 -04:00

220 lines
5.6 KiB
C++

/*!
* @file Adafruit_UBloxDDC.cpp
*
* @section ddc_intro_sec Introduction
*
* This is a library for the u-blox GPS/RTK modules using I2C interface (DDC)
*
* Designed specifically to work with u-blox GPS/RTK modules
* like NEO-M8P, ZED-F9P, etc.
*
* @section ddc_dependencies Dependencies
*
* This library depends on:
* <a href="https://github.com/adafruit/Adafruit_BusIO">Adafruit_BusIO</a>
*
* @section ddc_author Author
*
* Written by Limor Fried/Ladyada for Adafruit Industries.
*
* @section ddc_license License
*
* MIT license, all text above must be included in any redistribution
*/
#include "Adafruit_UBloxDDC.h"
/*!
* @brief Constructor
* @param address
* i2c address (default 0x42)
* @param wire
* TwoWire instance (default &Wire)
*/
Adafruit_UBloxDDC::Adafruit_UBloxDDC(uint8_t address, TwoWire *wire) {
_i2cDevice = new Adafruit_I2CDevice(address, wire);
}
/*!
* @brief Destructor - frees allocated resources
*/
Adafruit_UBloxDDC::~Adafruit_UBloxDDC() {
if (_i2cDevice) {
delete _i2cDevice;
}
}
/*!
* @brief Initializes the GPS module and I2C interface
* @return True if GPS module responds, false on any failure
*/
bool Adafruit_UBloxDDC::begin() { return _i2cDevice->begin(); }
/*!
* @brief Gets the number of bytes available for reading
* @return Number of bytes available, or 0 if no data or error
*/
int Adafruit_UBloxDDC::available() {
uint8_t buffer[2];
// Create a register for reading bytes available
Adafruit_BusIO_Register bytesAvailableReg =
Adafruit_BusIO_Register(_i2cDevice, REG_BYTES_AVAILABLE_MSB, 2);
if (!bytesAvailableReg.read(buffer, 2)) {
return 0;
}
uint16_t bytesAvailable = (uint16_t)buffer[0] << 8;
bytesAvailable |= buffer[1];
return bytesAvailable;
}
/*!
* @brief Reads a single byte from the data stream
* @return -1 if no data available or error, otherwise the byte read (0-255)
*/
int Adafruit_UBloxDDC::read() {
// If we have a peeked byte, return it
if (_hasPeeked) {
_hasPeeked = false;
return _lastByte;
}
uint8_t value;
// Create a register for the data stream
Adafruit_BusIO_Register dataStreamReg =
Adafruit_BusIO_Register(_i2cDevice, REG_DATA_STREAM, 1);
if (!dataStreamReg.read(&value, 1)) {
return -1;
}
return value;
}
/*!
* @brief Peek at the next available byte without removing it from the stream
* @return -1 if no data available or error, otherwise the byte (0-255)
*/
int Adafruit_UBloxDDC::peek() {
// If we've already peeked, return the last byte
if (_hasPeeked) {
return _lastByte;
}
// Otherwise, read a byte and store it
_lastByte = read();
if (_lastByte != -1) {
_hasPeeked = true;
}
return _lastByte;
}
/*!
* @brief Write a single byte (required by Stream but not suitable for I2C)
* @param val Byte to write
* @return Always returns 0 as single-byte writes aren't supported on I2C
*/
size_t Adafruit_UBloxDDC::write(uint8_t val) {
// Single-byte writes aren't suitable for I2C/DDC
// This shouldn't be called if properly using the multi-byte version
return 0;
}
/*!
* @brief Write multiple bytes at once (required for I2C/DDC)
* @param buffer Pointer to data buffer
* @param size Number of bytes to write
* @return Number of bytes written
*/
size_t Adafruit_UBloxDDC::write(const uint8_t *buffer, size_t size) {
// For I2C/DDC, we need at least 2 bytes for a write
if (size < 2) {
// Single-byte writes aren't supported
return 0;
}
// Use Adafruit_BusIO to handle the I2C transaction
if (_i2cDevice->write(buffer, size)) {
return size;
}
return 0;
}
/*!
* @brief Read multiple bytes from the data stream
* @param buffer Pointer to buffer to store data
* @param length Maximum number of bytes to read
* @return Number of bytes actually read, which may be less than requested
*/
uint16_t Adafruit_UBloxDDC::readBytes(uint8_t *buffer, uint16_t length) {
if (buffer == nullptr || length == 0) {
return 0;
}
uint16_t bytesRead = 0;
uint16_t bytesAvailable = available();
// Don't try to read more bytes than are available
length = min(length, bytesAvailable);
// Handle any peeked byte first
if (_hasPeeked && length > 0) {
buffer[0] = _lastByte;
_hasPeeked = false;
bytesRead = 1;
}
if (bytesRead >= length) {
return bytesRead;
}
// Create a register for the data stream
Adafruit_BusIO_Register dataStreamReg =
Adafruit_BusIO_Register(_i2cDevice, REG_DATA_STREAM, 1);
while (bytesRead < length) {
// Calculate chunk size (I2C has a limit on bytes per transfer)
uint16_t chunkSize = min((uint16_t)(length - bytesRead), (uint16_t)32);
if (!dataStreamReg.read(&buffer[bytesRead], chunkSize)) {
break;
}
bytesRead += chunkSize;
}
return bytesRead;
}
/*!
* @brief Read a complete message from the device
* @param buffer Pointer to buffer to store message data
* @param maxLength Maximum length of buffer
* @return Number of bytes read into the buffer
*/
uint16_t Adafruit_UBloxDDC::readMessage(uint8_t *buffer, uint16_t maxLength) {
uint16_t bytesAvailable = available();
if (bytesAvailable == 0) {
return 0;
}
// Limit to buffer size
uint16_t bytesToRead = min(bytesAvailable, maxLength);
return readBytes(buffer, bytesToRead);
}
/*!
* @brief Read a message into the internal buffer and return a pointer to it
* @param messageLength Pointer to variable to store message length
* @return Pointer to internal buffer containing the message
*/
uint8_t *Adafruit_UBloxDDC::readMessage(uint16_t *messageLength) {
*messageLength = readMessage(_buffer, MAX_BUFFER_SIZE);
return _buffer;
}