Skip to content

Add basic support NEO-D9C #145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions src/SparkFun_u-blox_GNSS_Arduino_Library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,16 @@ void SFE_UBLOX_GNSS::end(void)
packetUBXRXMPMPmessage = NULL; // Redundant?
}

if (packetUBXRXMQZSSL6message != NULL)
{
if (packetUBXRXMQZSSL6message->callbackData != NULL)
{
delete [] packetUBXRXMQZSSL6message->callbackData;
}
delete packetUBXRXMQZSSL6message;
packetUBXRXMQZSSL6message = NULL; // Redundant?
}

if (packetUBXRXMCOR != NULL)
{
if (packetUBXRXMCOR->callbackData != NULL)
Expand Down Expand Up @@ -1370,6 +1380,10 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
if ((packetUBXRXMPMP != NULL) || (packetUBXRXMPMPmessage != NULL))
result = true;
break;
case UBX_RXM_QZSSL6:
if (packetUBXRXMQZSSL6message != NULL)
result = true;
break;
case UBX_RXM_COR:
if (packetUBXRXMCOR != NULL)
result = true;
Expand Down Expand Up @@ -1545,6 +1559,9 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID)
case UBX_RXM_PMP:
maxSize = UBX_RXM_PMP_MAX_LEN;
break;
case UBX_RXM_QZSSL6:
maxSize = UBX_RXM_QZSSL6_MAX_LEN;
break;
case UBX_RXM_COR:
maxSize = UBX_RXM_COR_LEN;
break;
Expand Down Expand Up @@ -3830,6 +3847,31 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg)
packetUBXRXMPMPmessage->automaticFlags.flags.bits.callbackCopyValid = true; // Mark the data as valid
}
}
if (msg->id == UBX_RXM_QZSSL6)
// Note: length is variable with version 0x01
// Note: the field positions depend on the version
{
// Full QZSSL6 message, including Class, ID and checksum
for (int ch = 0; ch < UBX_RXM_QZSSL6_NUM_CHANNELS; ch ++) {
if (0 == (packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid & (1 << ch))) {

packetUBXRXMQZSSL6message->callbackData[ch].sync1 = UBX_SYNCH_1;
packetUBXRXMQZSSL6message->callbackData[ch].sync2 = UBX_SYNCH_2;
packetUBXRXMQZSSL6message->callbackData[ch].cls = UBX_CLASS_RXM;
packetUBXRXMQZSSL6message->callbackData[ch].ID = UBX_RXM_QZSSL6;
packetUBXRXMQZSSL6message->callbackData[ch].lengthLSB = msg->len & 0xFF;
packetUBXRXMQZSSL6message->callbackData[ch].lengthMSB = msg->len >> 8;

memcpy(packetUBXRXMQZSSL6message->callbackData[ch].payload, msg->payload, msg->len);

packetUBXRXMQZSSL6message->callbackData[ch].checksumA = msg->checksumA;
packetUBXRXMQZSSL6message->callbackData[ch].checksumB = msg->checksumB;

packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid |= (1 << ch);
break; // abort when added
}
}
}
else if (msg->id == UBX_RXM_COR)
{
// Parse various byte fields into storage - but only if we have memory allocated for it
Expand Down Expand Up @@ -5444,6 +5486,19 @@ void SFE_UBLOX_GNSS::checkCallbacks(void)
packetUBXRXMPMPmessage->callbackPointerPtr(packetUBXRXMPMPmessage->callbackData); // Call the callback
packetUBXRXMPMPmessage->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
}

if ((packetUBXRXMQZSSL6message != NULL) && // If RAM has been allocated for message storage
(packetUBXRXMQZSSL6message->callbackData != NULL) && // If RAM has been allocated for the copy of the data
(packetUBXRXMQZSSL6message->callbackPointerPtr != NULL)) // If the pointer to the callback has been defined
{
for (int ch = 0; ch < UBX_RXM_QZSSL6_NUM_CHANNELS; ch ++) {
if (packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid & (1 << ch)) // If the copy of the data is valid
{
packetUBXRXMQZSSL6message->callbackPointerPtr( &packetUBXRXMQZSSL6message->callbackData[ch] ); // Call the callback
packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid &= ~(1 << ch); // clear it
}
}
}

if ((packetUBXRXMCOR != NULL) // If RAM has been allocated for message storage
&& (packetUBXRXMCOR->callbackData != NULL) // If RAM has been allocated for the copy of the data
Expand Down Expand Up @@ -12561,6 +12616,53 @@ bool SFE_UBLOX_GNSS::initPacketUBXRXMPMPmessage()
return (true);
}

// ***** RXM QZSSL6 automatic support

// Callback receives a pointer to the data, instead of _all_ the data. Much kinder on the stack!
bool SFE_UBLOX_GNSS::setRXMQZSSL6messageCallbackPtr(void (*callbackPointer)(UBX_RXM_QZSSL6_message_data_t *))
{
if (packetUBXRXMQZSSL6message == NULL)
initPacketUBXRXMQZSSL6message(); // Check that RAM has been allocated for the data
if (packetUBXRXMQZSSL6message == NULL) // Only attempt this if RAM allocation was successful
return false;

if (packetUBXRXMQZSSL6message->callbackData == NULL) // Check if RAM has been allocated for the callback copy
{
packetUBXRXMQZSSL6message->callbackData = new UBX_RXM_QZSSL6_message_data_t[UBX_RXM_QZSSL6_NUM_CHANNELS]; // Allocate RAM for the main struct
}

if (packetUBXRXMQZSSL6message->callbackData == NULL)
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("setAutoRXMQZSSL6messagecallbackPtr: RAM alloc failed!"));
#endif
return (false);
}

packetUBXRXMQZSSL6message->callbackPointerPtr = callbackPointer;
return (true);
}

// PRIVATE: Allocate RAM for packetUBXRXMQZSSL6message and initialize it
bool SFE_UBLOX_GNSS::initPacketUBXRXMQZSSL6message()
{
packetUBXRXMQZSSL6message = new UBX_RXM_QZSSL6_message_t; // Allocate RAM for the main struct
if (packetUBXRXMQZSSL6message == NULL)
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("initPacketUBXRXMQZSSL6message: RAM alloc failed!"));
#endif
return (false);
}
packetUBXRXMQZSSL6message->automaticFlags.flags.all = 0;
packetUBXRXMQZSSL6message->callbackPointerPtr = NULL;
packetUBXRXMQZSSL6message->callbackData = NULL;
return (true);
}


bool SFE_UBLOX_GNSS::setRXMCORcallbackPtr(void (*callbackPointer)(UBX_RXM_COR_data_t *))
{
if (packetUBXRXMCOR == NULL)
Expand Down
9 changes: 9 additions & 0 deletions src/SparkFun_u-blox_GNSS_Arduino_Library.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ const uint8_t UBX_NAV_AOPSTATUS = 0x60; // AssistNow Autonomous status
const uint8_t UBX_RXM_COR = 0x34; // Differential correction input status
const uint8_t UBX_RXM_MEASX = 0x14; // Satellite Measurements for RRLP
const uint8_t UBX_RXM_PMP = 0x72; // PMP raw data (NEO-D9S) (two different versions) (packet size for version 0x01 is variable)
const uint8_t UBX_RXM_QZSSL6 = 0x73; // QZSSL6 data (NEO-D9C)
const uint8_t UBX_RXM_PMREQ = 0x41; // Requests a Power Management task (two different packet sizes)
const uint8_t UBX_RXM_RAWX = 0x15; // Multi-GNSS Raw Measurement Data
const uint8_t UBX_RXM_RLM = 0x59; // Galileo SAR Short-RLM report (two different packet sizes)
Expand Down Expand Up @@ -1163,6 +1164,12 @@ class SFE_UBLOX_GNSS
bool setRXMPMPcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_data_t *)); // Callback receives a pointer to the data, instead of _all_ the data. Much kinder on the stack!
bool setRXMPMPmessageCallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_message_data_t *)); // Use this if you want all of the PMP message (including sync chars, checksum, etc.) to push to a GNSS

// Configure a callback for the UBX-RXM-QZSSL6 messages produced by the NEO-D9C
// Note: on the NEO-D9C, the UBX-RXM-QZSSL6 messages are enabled by default on all ports.
// You can disable them by calling (e.g.) setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C, 0)
// The NEO-D9C does not support UBX-CFG-MSG
bool setRXMQZSSL6messageCallbackPtr(void (*callbackPointerPtr)(UBX_RXM_QZSSL6_message_data_t *)); // Use this if you want all of the QZSSL6 message (including sync chars, checksum, etc.) to push to a GNSS

bool setRXMCORcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_COR_data_t *)); // RXM COR

bool getRXMSFRBX(uint16_t maxWait = defaultMaxWait); // RXM SFRBX
Expand Down Expand Up @@ -1518,6 +1525,7 @@ class SFE_UBLOX_GNSS

UBX_RXM_PMP_t *packetUBXRXMPMP = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_PMP_message_t *packetUBXRXMPMPmessage = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_QZSSL6_message_t *packetUBXRXMQZSSL6message = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_COR_t *packetUBXRXMCOR = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_SFRBX_t *packetUBXRXMSFRBX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_RAWX_t *packetUBXRXMRAWX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
Expand Down Expand Up @@ -1617,6 +1625,7 @@ class SFE_UBLOX_GNSS
bool initPacketUBXNAVAOPSTATUS(); // Allocate RAM for packetUBXNAVAOPSTATUS and initialize it
bool initPacketUBXRXMPMP(); // Allocate RAM for packetUBXRXMPMP and initialize it
bool initPacketUBXRXMPMPmessage(); // Allocate RAM for packetUBXRXMPMPRaw and initialize it
bool initPacketUBXRXMQZSSL6message(); // Allocate RAM for packetUBXRXMQZSSL6raw and initialize it
bool initPacketUBXRXMCOR(); // Allocate RAM for packetUBXRXMCOR and initialize it
bool initPacketUBXRXMSFRBX(); // Allocate RAM for packetUBXRXMSFRBX and initialize it
bool initPacketUBXRXMRAWX(); // Allocate RAM for packetUBXRXMRAWX and initialize it
Expand Down
16 changes: 16 additions & 0 deletions src/u-blox_config_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,14 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART1 = 0x20910323; // Output rate o
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART2 = 0x20910324; // Output rate of the UBX_MON_PMP message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_USB = 0x20910325; // Output rate of the UBX_MON_PMP message on port USB

// Additional CFG_MSGOUT keys for the NEO-D9S
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C = 0x2091033f; // Output rate of the UBX_RXM_QZSSL6 message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_SPI = 0x2091033e; // Output rate of the UBX_RXM_QZSSL6 message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART1 = 0x2091033b; // Output rate of the UBX_RXM_QZSSL6 message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART2 = 0x2091033c; // Output rate of the UBX_RXM_QZSSL6 message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_USB = 0x2091033d; // Output rate of the UBX_RXM_QZSSL6 message on port USB

// CFG-NAV2: Secondary output configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_NAV2_OUT_ENABLED = 0x10170001; // Enable secondary (NAV2) output
Expand Down Expand Up @@ -928,6 +936,14 @@ const uint32_t UBLOX_CFG_PMP_DESCRAMBLER_INIT = 0x30b10015; // Descrambler init
const uint32_t UBLOX_CFG_PMP_USE_PRESCRAMBLING = 0x10b10019; // Use prescrambling. Enables/disables the prescrambling.
const uint32_t UBLOX_CFG_PMP_UNIQUE_WORD = 0x50b1001a; // Unique word. Defines value of unique word.

// CFG-QZSS-L6: QZSS system configuration configuration (NEO-D9C)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_QZSSL6_SVIDA = 0x20370020; // QZSS L6 SV Id to be decoded by channel A
const uint32_t UBLOX_CFG_QZSSL6_SVIDB = 0x20370030; // QZSS L6 SV Id to be decoded by channel B
const uint32_t UBLOX_CFG_QZSSL6_MSGA = 0x20370050; // QZSS L6 messages to be decoded by channel A
const uint32_t UBLOX_CFG_QZSSL6_MSGB = 0x20370060; // QZSS L6 messages to be decoded by channel B
const uint32_t UBLOX_CFG_QZSSL6_RSDECODER = 0x20370080; // QZSS L6 message Reed-Solomon decoder mode

// CFG-QZSS: QZSS system configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_QZSS_USE_SLAS_DGNSS = 0x10370005; // Apply QZSS SLAS DGNSS corrections
Expand Down
56 changes: 56 additions & 0 deletions src/u-blox_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,62 @@ typedef struct
UBX_RXM_PMP_message_data_t *callbackData;
} UBX_RXM_PMP_message_t;

// UBX-RXM-QZSSL6 (0x02 0x73): QZSS L6 raw data (D9C modules)
#define UBX_RXM_QZSSL6_NUM_CHANNELS 2
const uint16_t UBX_RXM_QZSSL6_DATALEN = 250;
const uint16_t UBX_RXM_QZSSL6_MAX_LEN = UBX_RXM_QZSSL6_DATALEN + 14;

typedef struct
{
uint8_t version; // Message version (0x00 / 0x01)
uint8_t svId; // Satellite identifier
uint16_t cno; // Mean C/N0
uint32_t timeTag; // Time since startup when frame started : ms
uint8_t groupDelay; // L6 group delay w.r.t. L2 on channel
uint8_t bitErrCorr; // Number of bit errors corrected by Reed-Solomon decoder
uint16_t chInfo; // Information about receiver channel associated with a received QZSS L6 message
uint8_t reserved0[2]; // Reserved
uint8_t msgBytes[UBX_RXM_QZSSL6_DATALEN]; // Bytes in a QZSS L6 message
} UBX_RXM_QZSSL6_data_t;

struct ubxQZSSL6AutomaticFlags
{
union
{
uint8_t all;
struct
{
uint8_t automatic : 1; // Will this message be delivered and parsed "automatically" (without polling)
uint8_t implicitUpdate : 1; // Is the update triggered by accessing stale data (=true) or by a call to checkUblox (=false)
uint8_t addToFileBuffer : 1; // Should the raw UBX data be added to the file buffer?
uint8_t callbackCopyValid : UBX_RXM_QZSSL6_NUM_CHANNELS; // Is the copies of the data structs used by the callback valid/fresh?
} bits;
} flags;
};

// Define a struct to hold the entire QZSSL6 message so the whole thing can be pushed to a GNSS.
// Remember that the length of the payload could be variable (with version 1 messages).
typedef struct
{
uint8_t sync1; // 0xB5
uint8_t sync2; // 0x62
uint8_t cls;
uint8_t ID;
uint8_t lengthLSB;
uint8_t lengthMSB;
uint8_t payload[UBX_RXM_QZSSL6_MAX_LEN];
uint8_t checksumA;
uint8_t checksumB;
} UBX_RXM_QZSSL6_message_data_t;

// The QZSSL6 data can only be accessed via a callback. QZSSL6 cannot be polled.
typedef struct
{
ubxQZSSL6AutomaticFlags automaticFlags;
void (*callbackPointerPtr)(UBX_RXM_QZSSL6_message_data_t *);
UBX_RXM_QZSSL6_message_data_t *callbackData;
} UBX_RXM_QZSSL6_message_t;

// CFG-specific structs

// UBX-CFG-PRT (0x06 0x00): Port configuration
Expand Down