diff --git a/Adafruit_UBX.cpp b/Adafruit_UBX.cpp index 49d1be8..c16b46f 100644 --- a/Adafruit_UBX.cpp +++ b/Adafruit_UBX.cpp @@ -1,32 +1,32 @@ /*! * @file Adafruit_UBX.cpp - * + * * @mainpage Arduino library for UBX protocol from u-blox GPS/RTK modules - * + * * @section intro_sec Introduction - * - * This is a library for parsing UBX protocol messages from u-blox GPS/RTK modules. - * It works with any Stream-based interface including UART and DDC (I2C). - * - * Designed specifically to work with u-blox GPS/RTK modules + * + * This is a library for parsing UBX protocol messages from u-blox GPS/RTK + * modules. It works with any Stream-based interface including UART and DDC + * (I2C). + * + * Designed specifically to work with u-blox GPS/RTK modules * like NEO-M8P, ZED-F9P, etc. - * + * * @section author Author - * + * * Written by Limor Fried/Ladyada for Adafruit Industries. - * + * * @section license License - * + * * MIT license, all text above must be included in any redistribution */ #include "Adafruit_UBX.h" - - /*! * @brief Constructor - * @param stream Reference to a Stream object (Serial, Adafruit_UBloxDDC, etc.) + * @param stream Reference to a Stream object (Serial, Adafruit_UBloxDDC, + * etc.) */ Adafruit_UBX::Adafruit_UBX(Stream &stream) { _stream = &stream; @@ -42,9 +42,6 @@ bool Adafruit_UBX::begin() { return true; } - - - /*! * @brief Configure the GPS module to output only UBX protocol (disables NMEA) * @param portID Port identifier (UBX_PORT_DDC, UBX_PORT_UART1, etc.) @@ -52,58 +49,60 @@ bool Adafruit_UBX::begin() { * @param timeout_ms Maximum time to wait for acknowledgment in milliseconds * @return UBXSendStatus indicating success, failure, or timeout */ -UBXSendStatus Adafruit_UBX::setUBXOnly(UBXPortId portID, bool checkAck, uint16_t timeout_ms) { +UBXSendStatus Adafruit_UBX::setUBXOnly(UBXPortId portID, bool checkAck, + uint16_t timeout_ms) { UBX_CFG_PRT_t cfgPrt; - + // Zero out the structure memset(&cfgPrt, 0, sizeof(cfgPrt)); - + // Set the port ID cfgPrt.fields.portID = portID; - + // Configure the port appropriately switch (portID) { - case UBX_PORT_DDC: // I2C/DDC port - // Set the I2C address to 0x42 (the default) - // For DDC, the mode field contains the I2C address in bits 7:1 - cfgPrt.fields.mode = 0x42 << 1; // 0x84 - - // Set protocol masks to UBX only - cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; - cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; - break; - - case UBX_PORT_UART1: // Fall through - case UBX_PORT_UART2: // UART ports - // Keep current baud rate (baudRate = 0 keeps current setting) - // Set 8N1 mode for binary protocol - cfgPrt.fields.mode = UBX_UART_MODE_8N1; - // Set protocol masks to UBX only - cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; - cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; - break; - - case UBX_PORT_USB: // USB port - // Set protocol masks to UBX only - cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; - cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; - break; - - case UBX_PORT_SPI: // SPI port - // Set protocol masks to UBX only - cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; - break; - - default: - if (verbose_debug > 0) { - Serial.println(F("UBX: Invalid port ID")); - } - return UBX_SEND_FAIL; // Invalid port ID + case UBX_PORT_DDC: // I2C/DDC port + // Set the I2C address to 0x42 (the default) + // For DDC, the mode field contains the I2C address in bits 7:1 + cfgPrt.fields.mode = 0x42 << 1; // 0x84 + + // Set protocol masks to UBX only + cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; + cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; + break; + + case UBX_PORT_UART1: // Fall through + case UBX_PORT_UART2: // UART ports + // Keep current baud rate (baudRate = 0 keeps current setting) + // Set 8N1 mode for binary protocol + cfgPrt.fields.mode = UBX_UART_MODE_8N1; + // Set protocol masks to UBX only + cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; + cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; + break; + + case UBX_PORT_USB: // USB port + // Set protocol masks to UBX only + cfgPrt.fields.inProtoMask = UBX_PROTOCOL_UBX; + cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; + break; + + case UBX_PORT_SPI: // SPI port + // Set protocol masks to UBX only + cfgPrt.fields.outProtoMask = UBX_PROTOCOL_UBX; + break; + + default: + if (verbose_debug > 0) { + Serial.println(F("UBX: Invalid port ID")); + } + return UBX_SEND_FAIL; // Invalid port ID } - + // Send the message and wait for acknowledgment if requested if (checkAck) { - return sendMessageWithAck(UBX_CLASS_CFG, UBX_CFG_PRT, cfgPrt.raw, sizeof(cfgPrt), timeout_ms); + return sendMessageWithAck(UBX_CLASS_CFG, UBX_CFG_PRT, cfgPrt.raw, + sizeof(cfgPrt), timeout_ms); } else { if (sendMessage(UBX_CLASS_CFG, UBX_CFG_PRT, cfgPrt.raw, sizeof(cfgPrt))) { return UBX_SEND_SUCCESS; @@ -113,12 +112,10 @@ UBXSendStatus Adafruit_UBX::setUBXOnly(UBXPortId portID, bool checkAck, uint16_t } } - - - /*! * @brief Sets the callback function for UBX messages - * @param callback Function pointer to call when a complete UBX message is received + * @param callback Function pointer to call when a complete UBX message is + * received */ void Adafruit_UBX::setMessageCallback(UBXMessageCallback callback) { onUBXMessage = callback; @@ -140,10 +137,11 @@ void Adafruit_UBX::resetParser() { * @param checksumA Reference to store the first checksum byte * @param checksumB Reference to store the second checksum byte */ -void Adafruit_UBX::calculateChecksum(uint8_t *buffer, uint16_t len, uint8_t &checksumA, uint8_t &checksumB) { +void Adafruit_UBX::calculateChecksum(uint8_t *buffer, uint16_t len, + uint8_t &checksumA, uint8_t &checksumB) { checksumA = 0; checksumB = 0; - + for (uint16_t i = 0; i < len; i++) { checksumA += buffer[i]; checksumB += checksumA; @@ -156,150 +154,158 @@ void Adafruit_UBX::calculateChecksum(uint8_t *buffer, uint16_t len, uint8_t &che */ bool Adafruit_UBX::checkMessages() { bool messageReceived = false; - + // Process all available bytes while (_stream->available()) { uint8_t incomingByte = _stream->read(); - + // State machine for UBX protocol parsing switch (_parserState) { - case WAIT_SYNC_1: - if (incomingByte == UBX_SYNC_CHAR_1) { - _parserState = WAIT_SYNC_2; - _buffer[0] = incomingByte; // Store for checksum calculation - } - break; - - case WAIT_SYNC_2: - if (incomingByte == UBX_SYNC_CHAR_2) { - _parserState = GET_CLASS; - _buffer[1] = incomingByte; // Store for checksum calculation - } else { - resetParser(); // Invalid sync char, reset - } - break; - - case GET_CLASS: - _msgClass = incomingByte; - _buffer[2] = incomingByte; // Store for checksum calculation - _parserState = GET_ID; - break; - - case GET_ID: - _msgId = incomingByte; - _buffer[3] = incomingByte; // Store for checksum calculation - _parserState = GET_LENGTH_1; - break; - - case GET_LENGTH_1: - _payloadLength = incomingByte; - _buffer[4] = incomingByte; // Store for checksum calculation - _parserState = GET_LENGTH_2; - break; - - case GET_LENGTH_2: - _payloadLength |= (incomingByte << 8); - _buffer[5] = incomingByte; // Store for checksum calculation - - if (_payloadLength > MAX_PAYLOAD_SIZE) { - resetParser(); // Payload too large, reset - } else { - _payloadCounter = 0; - _parserState = GET_PAYLOAD; - } - break; - - case GET_PAYLOAD: - if (_payloadCounter < _payloadLength) { - _buffer[6 + _payloadCounter] = incomingByte; - _payloadCounter++; - - if (_payloadCounter == _payloadLength) { - _parserState = GET_CHECKSUM_A; - } - } - break; - - case GET_CHECKSUM_A: - // Calculate expected checksum - calculateChecksum(_buffer + 2, _payloadLength + 4, _checksumA, _checksumB); - - if (incomingByte == _checksumA) { - _parserState = GET_CHECKSUM_B; // Checksum A matches - } else { - resetParser(); // Invalid checksum, reset - } - break; - - case GET_CHECKSUM_B: - if (incomingByte == _checksumB) { - // We have a valid message! - if (onUBXMessage != NULL) { - onUBXMessage(_msgClass, _msgId, _payloadLength, _buffer + 6); // Call the callback with the message - } - messageReceived = true; + case WAIT_SYNC_1: + if (incomingByte == UBX_SYNC_CHAR_1) { + _parserState = WAIT_SYNC_2; + _buffer[0] = incomingByte; // Store for checksum calculation + } + break; - _lastMsgClass = _msgClass; - _lastMsgId = _msgId; - _lastPayloadLength = _payloadLength; - - // Store a small copy of the payload if it's within size limits - if (_payloadLength <= sizeof(_lastPayload)) { - memcpy(_lastPayload, _buffer + 6, _payloadLength); - } + case WAIT_SYNC_2: + if (incomingByte == UBX_SYNC_CHAR_2) { + _parserState = GET_CLASS; + _buffer[1] = incomingByte; // Store for checksum calculation + } else { + resetParser(); // Invalid sync char, reset + } + break; - if (verbose_debug > 0) { - Serial.print("UBX RX: "); - - // Print header (sync chars, class, id, length) - Serial.print("HDR[B5 62 "); - if (_msgClass < 0x10) Serial.print("0"); - Serial.print(_msgClass, HEX); - Serial.print(" "); - if (_msgId < 0x10) Serial.print("0"); - Serial.print(_msgId, HEX); - Serial.print(" "); - - uint8_t lenLSB = _payloadLength & 0xFF; - uint8_t lenMSB = (_payloadLength >> 8) & 0xFF; - if (lenLSB < 0x10) Serial.print("0"); - Serial.print(lenLSB, HEX); - Serial.print(" "); - if (lenMSB < 0x10) Serial.print("0"); - Serial.print(lenMSB, HEX); - Serial.print("] "); - - // Print payload if verbose debug is enabled - if (verbose_debug > 1 && _payloadLength > 0) { - Serial.print("PL["); - for (uint16_t i = 0; i < _payloadLength; i++) { - if (_buffer[6 + i] < 0x10) Serial.print("0"); - Serial.print(_buffer[6 + i], HEX); - Serial.print(" "); - } - Serial.print("] "); + case GET_CLASS: + _msgClass = incomingByte; + _buffer[2] = incomingByte; // Store for checksum calculation + _parserState = GET_ID; + break; + + case GET_ID: + _msgId = incomingByte; + _buffer[3] = incomingByte; // Store for checksum calculation + _parserState = GET_LENGTH_1; + break; + + case GET_LENGTH_1: + _payloadLength = incomingByte; + _buffer[4] = incomingByte; // Store for checksum calculation + _parserState = GET_LENGTH_2; + break; + + case GET_LENGTH_2: + _payloadLength |= (incomingByte << 8); + _buffer[5] = incomingByte; // Store for checksum calculation + + if (_payloadLength > MAX_PAYLOAD_SIZE) { + resetParser(); // Payload too large, reset + } else { + _payloadCounter = 0; + _parserState = GET_PAYLOAD; + } + break; + + case GET_PAYLOAD: + if (_payloadCounter < _payloadLength) { + _buffer[6 + _payloadCounter] = incomingByte; + _payloadCounter++; + + if (_payloadCounter == _payloadLength) { + _parserState = GET_CHECKSUM_A; + } + } + break; + + case GET_CHECKSUM_A: + // Calculate expected checksum + calculateChecksum(_buffer + 2, _payloadLength + 4, _checksumA, + _checksumB); + + if (incomingByte == _checksumA) { + _parserState = GET_CHECKSUM_B; // Checksum A matches + } else { + resetParser(); // Invalid checksum, reset + } + break; + + case GET_CHECKSUM_B: + if (incomingByte == _checksumB) { + // We have a valid message! + if (onUBXMessage != NULL) { + onUBXMessage(_msgClass, _msgId, _payloadLength, + _buffer + 6); // Call the callback with the message + } + messageReceived = true; + + _lastMsgClass = _msgClass; + _lastMsgId = _msgId; + _lastPayloadLength = _payloadLength; + + // Store a small copy of the payload if it's within size limits + if (_payloadLength <= sizeof(_lastPayload)) { + memcpy(_lastPayload, _buffer + 6, _payloadLength); + } + + if (verbose_debug > 0) { + Serial.print("UBX RX: "); + + // Print header (sync chars, class, id, length) + Serial.print("HDR[B5 62 "); + if (_msgClass < 0x10) + Serial.print("0"); + Serial.print(_msgClass, HEX); + Serial.print(" "); + if (_msgId < 0x10) + Serial.print("0"); + Serial.print(_msgId, HEX); + Serial.print(" "); + + uint8_t lenLSB = _payloadLength & 0xFF; + uint8_t lenMSB = (_payloadLength >> 8) & 0xFF; + if (lenLSB < 0x10) + Serial.print("0"); + Serial.print(lenLSB, HEX); + Serial.print(" "); + if (lenMSB < 0x10) + Serial.print("0"); + Serial.print(lenMSB, HEX); + Serial.print("] "); + + // Print payload if verbose debug is enabled + if (verbose_debug > 1 && _payloadLength > 0) { + Serial.print("PL["); + for (uint16_t i = 0; i < _payloadLength; i++) { + if (_buffer[6 + i] < 0x10) + Serial.print("0"); + Serial.print(_buffer[6 + i], HEX); + Serial.print(" "); } - - // Print checksum - Serial.print("CS["); - if (_checksumA < 0x10) Serial.print("0"); - Serial.print(_checksumA, HEX); - Serial.print(" "); - if (_checksumB < 0x10) Serial.print("0"); - Serial.print(_checksumB, HEX); - Serial.println("]"); + Serial.print("] "); } + + // Print checksum + Serial.print("CS["); + if (_checksumA < 0x10) + Serial.print("0"); + Serial.print(_checksumA, HEX); + Serial.print(" "); + if (_checksumB < 0x10) + Serial.print("0"); + Serial.print(_checksumB, HEX); + Serial.println("]"); } - - resetParser(); // Reset for next message - break; + } + + resetParser(); // Reset for next message + break; } } - + return messageReceived; } - /*! * @brief Send a UBX message and wait for acknowledgment * @param msgClass Message class @@ -309,7 +315,10 @@ bool Adafruit_UBX::checkMessages() { * @param timeout_ms Maximum time to wait for acknowledgment * @return UBXSendStatus indicating success, failure, or timeout */ -UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, uint8_t *payload, uint16_t length, uint16_t timeout_ms = 500) { +UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, + uint8_t *payload, + uint16_t length, + uint16_t timeout_ms = 500) { // First send the message if (!sendMessage(msgClass, msgId, payload, length)) { if (verbose_debug > 0) { @@ -317,9 +326,9 @@ UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, } return UBX_SEND_FAIL; } - + uint32_t startTime = millis(); - + // Check for messages until timeout while ((millis() - startTime) < timeout_ms) { // Process incoming bytes @@ -332,10 +341,12 @@ UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, if (_lastPayload[0] == msgClass && _lastPayload[1] == msgId) { if (verbose_debug > 0) { Serial.print(F("UBX ACK: SUCCESS for message class 0x")); - if (msgClass < 0x10) Serial.print("0"); + if (msgClass < 0x10) + Serial.print("0"); Serial.print(msgClass, HEX); Serial.print(" ID 0x"); - if (msgId < 0x10) Serial.print("0"); + if (msgId < 0x10) + Serial.print("0"); Serial.println(msgId, HEX); } return UBX_SEND_SUCCESS; @@ -345,10 +356,12 @@ UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, if (_lastPayload[0] == msgClass && _lastPayload[1] == msgId) { if (verbose_debug > 0) { Serial.print(F("UBX ACK: NAK for message class 0x")); - if (msgClass < 0x10) Serial.print("0"); + if (msgClass < 0x10) + Serial.print("0"); Serial.print(msgClass, HEX); Serial.print(" ID 0x"); - if (msgId < 0x10) Serial.print("0"); + if (msgId < 0x10) + Serial.print("0"); Serial.println(msgId, HEX); } return UBX_SEND_NAK; @@ -356,96 +369,105 @@ UBXSendStatus Adafruit_UBX::sendMessageWithAck(uint8_t msgClass, uint8_t msgId, } } } - + // Short delay delay(1); } - + if (verbose_debug > 0) { - Serial.print(F("UBX ACK: TIMEOUT waiting for ACK/NAK for message class 0x")); - if (msgClass < 0x10) Serial.print("0"); + Serial.print( + F("UBX ACK: TIMEOUT waiting for ACK/NAK for message class 0x")); + if (msgClass < 0x10) + Serial.print("0"); Serial.print(msgClass, HEX); Serial.print(" ID 0x"); - if (msgId < 0x10) Serial.print("0"); + if (msgId < 0x10) + Serial.print("0"); Serial.println(msgId, HEX); } - + return UBX_SEND_TIMEOUT; } - /*! * @brief Send a UBX message to the GPS module * @param msgClass Message class * @param msgId Message ID - * @param payload Pointer to the payload data (can be NULL for zero-length payload) + * @param payload Pointer to the payload data (can be NULL for zero-length + * payload) * @param length Length of payload * @return True if message was sent successfully */ -bool Adafruit_UBX::sendMessage(uint8_t msgClass, uint8_t msgId, uint8_t *payload, uint16_t length) { - // Buffer for message (2 sync chars + class + id + 2 length bytes + payload + 2 checksum bytes) +bool Adafruit_UBX::sendMessage(uint8_t msgClass, uint8_t msgId, + uint8_t *payload, uint16_t length) { + // Buffer for message (2 sync chars + class + id + 2 length bytes + payload + + // 2 checksum bytes) uint8_t msgBuffer[length + 8]; - + // Sync characters msgBuffer[0] = UBX_SYNC_CHAR_1; msgBuffer[1] = UBX_SYNC_CHAR_2; - + // Message class and ID msgBuffer[2] = msgClass; msgBuffer[3] = msgId; - + // Length (little endian) msgBuffer[4] = length & 0xFF; msgBuffer[5] = (length >> 8) & 0xFF; - + // Payload if (payload != NULL && length > 0) { memcpy(&msgBuffer[6], payload, length); } - + // Calculate checksum uint8_t checksumA, checksumB; calculateChecksum(&msgBuffer[2], length + 4, checksumA, checksumB); - + msgBuffer[6 + length] = checksumA; msgBuffer[7 + length] = checksumB; - + // Debug output if (verbose_debug > 0) { Serial.print("UBX TX: "); - + // Print header (sync chars, class, id, length) Serial.print("HDR["); for (int i = 0; i < 6; i++) { - if (msgBuffer[i] < 0x10) Serial.print("0"); + if (msgBuffer[i] < 0x10) + Serial.print("0"); Serial.print(msgBuffer[i], HEX); Serial.print(" "); } Serial.print("] "); - + // Print payload if verbose debug is enabled if (verbose_debug > 1 && length > 0) { Serial.print("PL["); for (uint16_t i = 0; i < length; i++) { - if (msgBuffer[6 + i] < 0x10) Serial.print("0"); + if (msgBuffer[6 + i] < 0x10) + Serial.print("0"); Serial.print(msgBuffer[6 + i], HEX); Serial.print(" "); } Serial.print("] "); } - + // Print checksum Serial.print("CS["); - if (checksumA < 0x10) Serial.print("0"); + if (checksumA < 0x10) + Serial.print("0"); Serial.print(checksumA, HEX); Serial.print(" "); - if (checksumB < 0x10) Serial.print("0"); + if (checksumB < 0x10) + Serial.print("0"); Serial.print(checksumB, HEX); Serial.println("]"); } - + // Send the message size_t written = _stream->write(msgBuffer, length + 8); - + return (written == length + 8); } diff --git a/Adafruit_UBX.h b/Adafruit_UBX.h index e7f34b9..f6afc5e 100644 --- a/Adafruit_UBX.h +++ b/Adafruit_UBX.h @@ -1,98 +1,105 @@ /*! * @file Adafruit_UBX.h - * + * * Arduino library for parsing UBX protocol from u-blox GPS/RTK modules. - * + * * This library can use any Stream object as input (UART, DDC, or other). - * + * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * Written by Limor Fried/Ladyada for Adafruit Industries. - * + * * MIT license, all text here must be included in any redistribution. */ #ifndef ADAFRUIT_UBX_H #define ADAFRUIT_UBX_H +#include "Adafruit_uBlox_typedef.h" #include #include -#include "Adafruit_uBlox_typedef.h" // UBX protocol constants #define UBX_SYNC_CHAR_1 0xB5 // First UBX protocol sync char (�) #define UBX_SYNC_CHAR_2 0x62 // Second UBX protocol sync char (b) // UBX ACK Message IDs -#define UBX_ACK_NAK 0x00 // Message Not Acknowledged -#define UBX_ACK_ACK 0x01 // Message Acknowledged - -// Callback function type for UBX messages - defined at global scope so other classes can use it -typedef void (*UBXMessageCallback)(uint8_t msgClass, uint8_t msgId, uint16_t payloadLen, uint8_t *payload); +#define UBX_ACK_NAK 0x00 // Message Not Acknowledged +#define UBX_ACK_ACK 0x01 // Message Acknowledged +// Callback function type for UBX messages - defined at global scope so other +// classes can use it +typedef void (*UBXMessageCallback)(uint8_t msgClass, uint8_t msgId, + uint16_t payloadLen, uint8_t *payload); /*! * @brief Class for parsing UBX protocol messages from u-blox GPS/RTK modules */ class Adafruit_UBX { - public: - // Constructor - Adafruit_UBX(Stream &stream); - uint8_t verbose_debug = 0; // 0=off, 1=basic, 2=verbose +public: + // Constructor + Adafruit_UBX(Stream &stream); + uint8_t verbose_debug = 0; // 0=off, 1=basic, 2=verbose - // Basic methods - bool begin(); - - bool checkMessages(); // Message parsing - bool sendMessage(uint8_t msgClass, uint8_t msgId, uint8_t *payload, uint16_t length); // Send a UBX message - UBXSendStatus sendMessageWithAck(uint8_t msgClass, uint8_t msgId, uint8_t *payload, uint16_t length, uint16_t timeout_ms = 500); + // Basic methods + bool begin(); - // Configure port to use UBX protocol only (disable NMEA) - UBXSendStatus setUBXOnly(UBXPortId portID, bool checkAck = true, uint16_t timeout_ms = 500); + bool checkMessages(); // Message parsing + bool sendMessage(uint8_t msgClass, uint8_t msgId, uint8_t *payload, + uint16_t length); // Send a UBX message + UBXSendStatus sendMessageWithAck(uint8_t msgClass, uint8_t msgId, + uint8_t *payload, uint16_t length, + uint16_t timeout_ms = 500); - void setMessageCallback(UBXMessageCallback callback); // Set callback function - UBXMessageCallback onUBXMessage; // Callback for message received + // Configure port to use UBX protocol only (disable NMEA) + UBXSendStatus setUBXOnly(UBXPortId portID, bool checkAck = true, + uint16_t timeout_ms = 500); - private: - Stream *_stream; // Stream interface for reading data - - // Buffer for reading messages - static const uint16_t MAX_PAYLOAD_SIZE = 64; // Maximum UBX payload size - uint8_t _buffer[MAX_PAYLOAD_SIZE + 8]; // Buffer for message (header, payload, checksum) - - // Parser state machine - enum ParserState { - WAIT_SYNC_1, // Waiting for first sync char (0xB5) - WAIT_SYNC_2, // Waiting for second sync char (0x62) - GET_CLASS, // Reading message class - GET_ID, // Reading message ID - GET_LENGTH_1, // Reading length LSB - GET_LENGTH_2, // Reading length MSB - GET_PAYLOAD, // Reading payload - GET_CHECKSUM_A, // Reading checksum A - GET_CHECKSUM_B // Reading checksum B - }; - - ParserState _parserState = WAIT_SYNC_1; // Current state of the parser - uint8_t _msgClass; // Message class of current message - uint8_t _msgId; // Message ID of current message - uint16_t _payloadLength; // Length of current message payload - uint16_t _payloadCounter; // Counter for payload bytes received - uint8_t _checksumA; // Running checksum A - uint8_t _checksumB; // Running checksum B - - // Calculate checksum for a block of data - void calculateChecksum(uint8_t *buffer, uint16_t len, uint8_t &checksumA, uint8_t &checksumB); - - // Reset parser state - void resetParser(); + void setMessageCallback(UBXMessageCallback callback); // Set callback function + UBXMessageCallback onUBXMessage; // Callback for message received - // Add to private section of Adafruit_UBX.h - uint8_t _lastMsgClass; // Class of last message - uint8_t _lastMsgId; // ID of last message - uint16_t _lastPayloadLength; // Length of last message payload - uint8_t _lastPayload[8]; // Buffer for small payloads (like ACK messages) +private: + Stream *_stream; // Stream interface for reading data + + // Buffer for reading messages + static const uint16_t MAX_PAYLOAD_SIZE = 64; // Maximum UBX payload size + uint8_t _buffer[MAX_PAYLOAD_SIZE + + 8]; // Buffer for message (header, payload, checksum) + + // Parser state machine + enum ParserState { + WAIT_SYNC_1, // Waiting for first sync char (0xB5) + WAIT_SYNC_2, // Waiting for second sync char (0x62) + GET_CLASS, // Reading message class + GET_ID, // Reading message ID + GET_LENGTH_1, // Reading length LSB + GET_LENGTH_2, // Reading length MSB + GET_PAYLOAD, // Reading payload + GET_CHECKSUM_A, // Reading checksum A + GET_CHECKSUM_B // Reading checksum B + }; + + ParserState _parserState = WAIT_SYNC_1; // Current state of the parser + uint8_t _msgClass; // Message class of current message + uint8_t _msgId; // Message ID of current message + uint16_t _payloadLength; // Length of current message payload + uint16_t _payloadCounter; // Counter for payload bytes received + uint8_t _checksumA; // Running checksum A + uint8_t _checksumB; // Running checksum B + + // Calculate checksum for a block of data + void calculateChecksum(uint8_t *buffer, uint16_t len, uint8_t &checksumA, + uint8_t &checksumB); + + // Reset parser state + void resetParser(); + + // Add to private section of Adafruit_UBX.h + uint8_t _lastMsgClass; // Class of last message + uint8_t _lastMsgId; // ID of last message + uint16_t _lastPayloadLength; // Length of last message payload + uint8_t _lastPayload[8]; // Buffer for small payloads (like ACK messages) }; #endif // ADAFRUIT_UBX_H diff --git a/Adafruit_UBloxDDC.cpp b/Adafruit_UBloxDDC.cpp index e01f132..c66d094 100644 --- a/Adafruit_UBloxDDC.cpp +++ b/Adafruit_UBloxDDC.cpp @@ -1,26 +1,26 @@ /*! * @file Adafruit_UBloxDDC.cpp - * + * * @mainpage Arduino library for u-blox GPS/RTK modules over DDC (I2C) - * + * * @section 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 + * + * Designed specifically to work with u-blox GPS/RTK modules * like NEO-M8P, ZED-F9P, etc. - * + * * @section dependencies Dependencies - * + * * This library depends on: * Adafruit_BusIO - * + * * @section author Author - * + * * Written by Limor Fried/Ladyada for Adafruit Industries. - * + * * @section license License - * + * * MIT license, all text above must be included in any redistribution */ @@ -50,9 +50,7 @@ Adafruit_UBloxDDC::~Adafruit_UBloxDDC() { * @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(); -} +bool Adafruit_UBloxDDC::begin() { return _i2cDevice->begin(); } /*! * @brief Gets the number of bytes available for reading @@ -60,17 +58,18 @@ bool Adafruit_UBloxDDC::begin() { */ 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); - + 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; } @@ -84,16 +83,17 @@ int Adafruit_UBloxDDC::read() { _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); - + Adafruit_BusIO_Register dataStreamReg = + Adafruit_BusIO_Register(_i2cDevice, REG_DATA_STREAM, 1); + if (!dataStreamReg.read(&value, 1)) { return -1; } - + return value; } @@ -106,13 +106,13 @@ int Adafruit_UBloxDDC::peek() { if (_hasPeeked) { return _lastByte; } - + // Otherwise, read a byte and store it _lastByte = read(); if (_lastByte != -1) { _hasPeeked = true; } - + return _lastByte; } @@ -139,7 +139,7 @@ size_t Adafruit_UBloxDDC::write(const uint8_t *buffer, size_t size) { // Single-byte writes aren't supported return 0; } - + // Use Adafruit_BusIO to handle the I2C transaction if (_i2cDevice->write(buffer, size)) { return size; @@ -153,42 +153,43 @@ size_t Adafruit_UBloxDDC::write(const uint8_t *buffer, size_t size) { * @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) { +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); - + 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(length - bytesRead, (uint16_t)32); - + if (!dataStreamReg.read(&buffer[bytesRead], chunkSize)) { break; } - + bytesRead += chunkSize; } - + return bytesRead; } @@ -198,13 +199,13 @@ uint16_t Adafruit_UBloxDDC::readBytes(uint8_t* buffer, uint16_t length) { * @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 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); @@ -215,8 +216,7 @@ uint16_t Adafruit_UBloxDDC::readMessage(uint8_t* buffer, uint16_t maxLength) { * @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) { +uint8_t *Adafruit_UBloxDDC::readMessage(uint16_t *messageLength) { *messageLength = readMessage(_buffer, MAX_BUFFER_SIZE); return _buffer; } - diff --git a/Adafruit_UBloxDDC.h b/Adafruit_UBloxDDC.h index 9067ffd..eb9f10b 100644 --- a/Adafruit_UBloxDDC.h +++ b/Adafruit_UBloxDDC.h @@ -1,68 +1,72 @@ /*! * @file Adafruit_UBloxDDC.h - * + * * Arduino library for interfacing with u-blox GPS/RTK modules over I2C (DDC). - * + * * This library implements the Stream interface, allowing it to be used with * existing GPS parsing libraries like TinyGPS++. - * + * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * Written by Limor Fried/Ladyada for Adafruit Industries. - * + * * MIT license, all text here must be included in any redistribution. */ #ifndef ADAFRUIT_UBLOXDDC_H #define ADAFRUIT_UBLOXDDC_H -#include -#include #include #include +#include +#include /*! * @brief Arduino library for interfacing with u-blox GPS/RTK modules over I2C */ class Adafruit_UBloxDDC : public Stream { - private: - Adafruit_I2CDevice *_i2cDevice; ///< Underlying I2C device - - // Register addresses - static const uint8_t REG_DATA_STREAM = 0xFF; ///< Register for reading data stream - static const uint8_t REG_BYTES_AVAILABLE_MSB = 0xFD; ///< MSB of bytes available - static const uint8_t REG_BYTES_AVAILABLE_LSB = 0xFE; ///< LSB of bytes available - - // Buffer for reading messages - static const uint16_t MAX_BUFFER_SIZE = 128; ///< Maximum buffer size for messages - uint8_t _buffer[MAX_BUFFER_SIZE]; ///< Internal buffer for messages - - // Last byte read for peek() implementation - int _lastByte = -1; ///< Last byte read by peek() - bool _hasPeeked = false; ///< Indicates if we have a peeked byte waiting +private: + Adafruit_I2CDevice *_i2cDevice; ///< Underlying I2C device - public: - // Constructor & destructor - Adafruit_UBloxDDC(uint8_t address = 0x42, TwoWire *wire = &Wire); - ~Adafruit_UBloxDDC(); - - // Basic methods - bool begin(); - - // Stream interface implementation - virtual int available() override; - virtual int read() override; - virtual int peek() override; - // Stream interface implementation - virtual size_t write(uint8_t) override; - virtual size_t write(const uint8_t *buffer, size_t size) override; - - // Additional methods - uint16_t readBytes(uint8_t* buffer, uint16_t length); - uint16_t readMessage(uint8_t* buffer, uint16_t maxLength); - uint8_t* readMessage(uint16_t* messageLength); + // Register addresses + static const uint8_t REG_DATA_STREAM = + 0xFF; ///< Register for reading data stream + static const uint8_t REG_BYTES_AVAILABLE_MSB = + 0xFD; ///< MSB of bytes available + static const uint8_t REG_BYTES_AVAILABLE_LSB = + 0xFE; ///< LSB of bytes available + + // Buffer for reading messages + static const uint16_t MAX_BUFFER_SIZE = + 128; ///< Maximum buffer size for messages + uint8_t _buffer[MAX_BUFFER_SIZE]; ///< Internal buffer for messages + + // Last byte read for peek() implementation + int _lastByte = -1; ///< Last byte read by peek() + bool _hasPeeked = false; ///< Indicates if we have a peeked byte waiting + +public: + // Constructor & destructor + Adafruit_UBloxDDC(uint8_t address = 0x42, TwoWire *wire = &Wire); + ~Adafruit_UBloxDDC(); + + // Basic methods + bool begin(); + + // Stream interface implementation + virtual int available() override; + virtual int read() override; + virtual int peek() override; + // Stream interface implementation + virtual size_t write(uint8_t) override; + virtual size_t write(const uint8_t *buffer, size_t size) override; + + // Additional methods + uint16_t readBytes(uint8_t *buffer, uint16_t length); + uint16_t readMessage(uint8_t *buffer, uint16_t maxLength); + uint8_t *readMessage(uint16_t *messageLength); }; #endif // ADAFRUIT_UBLOXDDC_H diff --git a/Adafruit_uBlox_Ubx_Messages.h b/Adafruit_uBlox_Ubx_Messages.h index 51663a6..cc62170 100644 --- a/Adafruit_uBlox_Ubx_Messages.h +++ b/Adafruit_uBlox_Ubx_Messages.h @@ -1,14 +1,14 @@ /*! * @file Adafruit_uBlox_Ubx_Messages.h - * + * * Pre-built UBX message payloads for common tasks - * + * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * Written by Brent Rubell for Adafruit Industries. - * + * * MIT license, all text here must be included in any redistribution. */ @@ -18,28 +18,41 @@ #include // NMEA Message Configuration Commands (CFG-MSG) -// Format: {msgClass, msgID, rate_I2C, rate_UART1, rate_UART2, rate_USB, rate_SPI, reserved} +// Format: {msgClass, msgID, rate_I2C, rate_UART1, rate_UART2, rate_USB, +// rate_SPI, reserved} // Enable specific NMEA message sentences to output on the DDC interface -static uint8_t UBX_CFG_MSG_NMEA_GGA_ENABLE[] = {0xF0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GLL_ENABLE[] = {0xF0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GSA_ENABLE[] = {0xF0, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GSV_ENABLE[] = {0xF0, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_RMC_ENABLE[] = {0xF0, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_VTG_ENABLE[] = {0xF0, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GGA_ENABLE[] = {0xF0, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GLL_ENABLE[] = {0xF0, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GSA_ENABLE[] = {0xF0, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GSV_ENABLE[] = {0xF0, 0x03, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_RMC_ENABLE[] = {0xF0, 0x04, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_VTG_ENABLE[] = {0xF0, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}; // Disable specific NMEA message sentences from outputting on the DDC interface -static uint8_t UBX_CFG_MSG_NMEA_GGA_DISABLE[] = {0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GLL_DISABLE[] = {0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GSA_DISABLE[] = {0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_GSV_DISABLE[] = {0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_RMC_DISABLE[] = {0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static uint8_t UBX_CFG_MSG_NMEA_VTG_DISABLE[] = {0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GGA_DISABLE[] = {0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GLL_DISABLE[] = {0xF0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GSA_DISABLE[] = {0xF0, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_GSV_DISABLE[] = {0xF0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_RMC_DISABLE[] = {0xF0, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +static uint8_t UBX_CFG_MSG_NMEA_VTG_DISABLE[] = {0xF0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; // Navigation Rate Configuration Commands (CFG-RATE) // Format: {measRate_ms (2 bytes), navRate, timeRef} -static uint8_t UBX_CFG_RATE_1HZ[] = {0xE8, 0x03, 0x01, 0x00, 0x01, 0x00}; -static uint8_t UBX_CFG_RATE_2HZ[] = {0xF4, 0x01, 0x01, 0x00, 0x01, 0x00}; -static uint8_t UBX_CFG_RATE_5HZ[] = {0xC8, 0x00, 0x01, 0x00, 0x01, 0x00}; +static uint8_t UBX_CFG_RATE_1HZ[] = {0xE8, 0x03, 0x01, 0x00, 0x01, 0x00}; +static uint8_t UBX_CFG_RATE_2HZ[] = {0xF4, 0x01, 0x01, 0x00, 0x01, 0x00}; +static uint8_t UBX_CFG_RATE_5HZ[] = {0xC8, 0x00, 0x01, 0x00, 0x01, 0x00}; static uint8_t UBX_CFG_RATE_10HZ[] = {0x64, 0x00, 0x01, 0x00, 0x01, 0x00}; #endif // ADAFRUIT_UBLOX_UBX_MESSAGES \ No newline at end of file diff --git a/Adafruit_uBlox_typedef.h b/Adafruit_uBlox_typedef.h index 2005019..7c00a8d 100644 --- a/Adafruit_uBlox_typedef.h +++ b/Adafruit_uBlox_typedef.h @@ -1,14 +1,14 @@ /*! * @file Adafruit_uBlox_typedef.h - * + * * Type definitions for u-blox GPS/RTK module messages - * + * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * Written by Limor Fried/Ladyada for Adafruit Industries. - * + * * MIT license, all text here must be included in any redistribution. */ @@ -19,41 +19,41 @@ // UBX Message Classes typedef enum { - UBX_CLASS_NAV = 0x01, // Navigation Results - UBX_CLASS_RXM = 0x02, // Receiver Manager Messages - UBX_CLASS_INF = 0x04, // Information Messages - UBX_CLASS_ACK = 0x05, // Acknowledgements - UBX_CLASS_CFG = 0x06, // Configuration - UBX_CLASS_UPD = 0x09, // Firmware Update - UBX_CLASS_MON = 0x0A, // Monitoring - UBX_CLASS_AID = 0x0B, // AssistNow Aiding - UBX_CLASS_TIM = 0x0D, // Timing - UBX_CLASS_ESF = 0x10, // External Sensor Fusion - UBX_CLASS_MGA = 0x13, // Multiple GNSS Assistance - UBX_CLASS_LOG = 0x21, // Logging - UBX_CLASS_SEC = 0x27, // Security - UBX_CLASS_HNR = 0x28, // High Rate Navigation - UBX_CLASS_NMEA = 0xF0 // NMEA Standard Messages + UBX_CLASS_NAV = 0x01, // Navigation Results + UBX_CLASS_RXM = 0x02, // Receiver Manager Messages + UBX_CLASS_INF = 0x04, // Information Messages + UBX_CLASS_ACK = 0x05, // Acknowledgements + UBX_CLASS_CFG = 0x06, // Configuration + UBX_CLASS_UPD = 0x09, // Firmware Update + UBX_CLASS_MON = 0x0A, // Monitoring + UBX_CLASS_AID = 0x0B, // AssistNow Aiding + UBX_CLASS_TIM = 0x0D, // Timing + UBX_CLASS_ESF = 0x10, // External Sensor Fusion + UBX_CLASS_MGA = 0x13, // Multiple GNSS Assistance + UBX_CLASS_LOG = 0x21, // Logging + UBX_CLASS_SEC = 0x27, // Security + UBX_CLASS_HNR = 0x28, // High Rate Navigation + UBX_CLASS_NMEA = 0xF0 // NMEA Standard Messages } UBXMessageClass; // UBX CFG Message IDs typedef enum { - UBX_CFG_PRT = 0x00, // Port Configuration - UBX_CFG_MSG = 0x01, // Message Configuration - UBX_CFG_RST = 0x04, // Reset Receiver - UBX_CFG_RATE = 0x08, // Navigation/Measurement Rate Settings - UBX_CFG_CFG = 0x09, // Clear, Save, and Load Configurations - UBX_CFG_NAVX5 = 0x23, // Navigation Engine Settings - UBX_CFG_GNSS = 0x3E, // GNSS Configuration - UBX_CFG_PMS = 0x86 // Power Mode Setup + UBX_CFG_PRT = 0x00, // Port Configuration + UBX_CFG_MSG = 0x01, // Message Configuration + UBX_CFG_RST = 0x04, // Reset Receiver + UBX_CFG_RATE = 0x08, // Navigation/Measurement Rate Settings + UBX_CFG_CFG = 0x09, // Clear, Save, and Load Configurations + UBX_CFG_NAVX5 = 0x23, // Navigation Engine Settings + UBX_CFG_GNSS = 0x3E, // GNSS Configuration + UBX_CFG_PMS = 0x86 // Power Mode Setup } UBXCfgMessageId; // Return values for functions that wait for acknowledgment typedef enum { - UBX_SEND_SUCCESS = 0, // Message was acknowledged (ACK) - UBX_SEND_NAK, // Message was not acknowledged (NAK) - UBX_SEND_FAIL, // Failed to send the message - UBX_SEND_TIMEOUT // Timed out waiting for ACK/NAK + UBX_SEND_SUCCESS = 0, // Message was acknowledged (ACK) + UBX_SEND_NAK, // Message was not acknowledged (NAK) + UBX_SEND_FAIL, // Failed to send the message + UBX_SEND_TIMEOUT // Timed out waiting for ACK/NAK } UBXSendStatus; // Port ID enum for different interfaces @@ -82,20 +82,21 @@ typedef enum { } UBXUARTMode; // Protocol flags for inProtoMask and outProtoMask -#define UBX_PROTOCOL_UBX 0x0001 // UBX protocol -#define UBX_PROTOCOL_NMEA 0x0002 // NMEA protocol -#define UBX_PROTOCOL_RTCM 0x0004 // RTCM2 protocol (only for inProtoMask) +#define UBX_PROTOCOL_UBX 0x0001 // UBX protocol +#define UBX_PROTOCOL_NMEA 0x0002 // NMEA protocol +#define UBX_PROTOCOL_RTCM 0x0004 // RTCM2 protocol (only for inProtoMask) #define UBX_PROTOCOL_RTCM3 0x0020 // RTCM3 protocol // CFG-PRT (Port Configuration) Message // Total size: 20 bytes typedef union { struct { - uint8_t portID; // Port identifier (0=DDC/I2C, 1=UART1, 2=UART2, 3=USB, 4=SPI) - uint8_t reserved1; // Reserved - uint16_t txReady; // TX ready PIN configuration - uint32_t mode; // UART mode (bit field) or Reserved for non-UART ports - uint32_t baudRate; // Baudrate in bits/second (UART only) + uint8_t + portID; // Port identifier (0=DDC/I2C, 1=UART1, 2=UART2, 3=USB, 4=SPI) + uint8_t reserved1; // Reserved + uint16_t txReady; // TX ready PIN configuration + uint32_t mode; // UART mode (bit field) or Reserved for non-UART ports + uint32_t baudRate; // Baudrate in bits/second (UART only) uint16_t inProtoMask; // Input protocol mask uint16_t outProtoMask; // Output protocol mask uint16_t flags; // Flags bit field