From 6d6b0e6bc15836610ee33ee8cbc81274e5e6a0e2 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 10:37:52 -0700 Subject: [PATCH 01/11] Add isBlocking Allow check to see if Unicore library needs lone control of serial hardware. --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 175 +++++++++--------- src/SparkFun_Unicore_GNSS_Arduino_Library.h | 132 ++++++------- 2 files changed, 159 insertions(+), 148 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index c2386ab..f5b07ac 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -81,14 +81,13 @@ //---------------------------------------- // parserTable index values -#define UM980_NMEA_PARSER_INDEX 0 -#define UM980_UNICORE_HASH_PARSER_INDEX 1 -#define UM980_RTCM_PARSER_INDEX 2 -#define UM980_UNICORE_BINARY_PARSER_INDEX 3 +#define UM980_NMEA_PARSER_INDEX 0 +#define UM980_UNICORE_HASH_PARSER_INDEX 1 +#define UM980_RTCM_PARSER_INDEX 2 +#define UM980_UNICORE_BINARY_PARSER_INDEX 3 // Build the table listing all of the parsers -SEMP_PARSE_ROUTINE const parserTable[] = -{ +SEMP_PARSE_ROUTINE const parserTable[] = { sempNmeaPreamble, sempUnicoreHashPreamble, sempRtcmPreamble, @@ -96,8 +95,7 @@ SEMP_PARSE_ROUTINE const parserTable[] = }; const int parserCount = sizeof(parserTable) / sizeof(parserTable[0]); -const char * const parserNames[] = -{ +const char *const parserNames[] = { "UN980 NMEA Parser", "UM980 Unicore Hash (#) Parser", "UM980 RTCM Parser", @@ -106,7 +104,7 @@ const char * const parserNames[] = const int parserNameCount = sizeof(parserNames) / sizeof(parserNames[0]); // Account for the largest message -#define BUFFER_LENGTH 3000 +#define BUFFER_LENGTH 3000 //---------------------------------------- // Globals @@ -161,7 +159,7 @@ bool badNmeaChecksum(SEMP_PARSE_STATE *parse) } // Translate the state value into an ASCII state name -const char * um980GetStateName(SEMP_PARSE_STATE *parse) +const char *um980GetStateName(SEMP_PARSE_STATE *parse) { const char *name; @@ -224,11 +222,9 @@ bool UM980::begin(HardwareSerial &serialPort, Print *parserDebug, Print *parserE _hwSerialPort = &serialPort; // Initialize the parser - _sempParse = sempBeginParser(parserTable, parserCount, - parserNames, parserNameCount, - 0, BUFFER_LENGTH, um980ProcessMessage, - "SFE_Unicore_GNSS_Library", parserError, - parserDebug, badNmeaChecksum); + _sempParse = + sempBeginParser(parserTable, parserCount, parserNames, parserNameCount, 0, BUFFER_LENGTH, um980ProcessMessage, + "SFE_Unicore_GNSS_Library", parserError, parserDebug, badNmeaChecksum); if (!_sempParse) { debugPrintf("UM980: Failed to initialize the parser!"); @@ -277,6 +273,14 @@ bool UM980::isConnected() return (false); } +// If another task outside of this library is accessing the same Serial hardware, it can +// check to see if this library currently needs exclusive read/write access for a short period. +// If isBlocking is true, external consumers should not read/write to the Serial hardware +bool UM980::isBlocking() +{ + return(unicoreLibrarySemaphoreBlock); +} + // Calling this function with nothing sets the debug port to Serial // You can also call it with other streams like Serial1, SerialUSB, etc. void UM980::enableDebugging(Print &debugPort) @@ -331,9 +335,8 @@ bool UM980::updateOnce() endName = um980GetStateName(_sempParse); // Display the parser state transition - debugPrintf("UM980: 0x%02x (%c), crc: 0x%08x, state: %s --> %s", - incoming, ((incoming >= ' ') && (incoming < 0x7f)) ? incoming : '.', - _sempParse->crc, startName, endName); + debugPrintf("UM980: 0x%02x (%c), crc: 0x%08x, state: %s --> %s", incoming, + ((incoming >= ' ') && (incoming < 0x7f)) ? incoming : '.', _sempParse->crc, startName, endName); } return (true); } @@ -380,7 +383,8 @@ void UM980::dumpBuffer(const uint8_t *buffer, uint16_t length) // Display the ASCII values for (index = 0; index < bytes; index++) - sprintf(&line[strlen(line)], "%c", ((buffer[index] < ' ') || (buffer[index] >= 0x7f)) ? '.' : buffer[index]); + sprintf(&line[strlen(line)], "%c", + ((buffer[index] < ' ') || (buffer[index] >= 0x7f)) ? '.' : buffer[index]); debugPrintf("%s", line); // Set the next line of data @@ -425,27 +429,23 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) ptrUM980->debugPrintf(""); switch (type) { - case UM980_NMEA_PARSER_INDEX: - ptrUM980->debugPrintf("Valid NMEA Sentence: %s, 0x%04x (%d) bytes", - sempNmeaGetSentenceName(parse), - parse->length, parse->length); - break; + case UM980_NMEA_PARSER_INDEX: + ptrUM980->debugPrintf("Valid NMEA Sentence: %s, 0x%04x (%d) bytes", sempNmeaGetSentenceName(parse), + parse->length, parse->length); + break; - case UM980_UNICORE_HASH_PARSER_INDEX: - ptrUM980->debugPrintf("Valid Unicore Hash (#) Sentence: %s, 0x%04x (%d) bytes", - sempUnicoreHashGetSentenceName(parse), - parse->length, parse->length); - break; + case UM980_UNICORE_HASH_PARSER_INDEX: + ptrUM980->debugPrintf("Valid Unicore Hash (#) Sentence: %s, 0x%04x (%d) bytes", + sempUnicoreHashGetSentenceName(parse), parse->length, parse->length); + break; - case UM980_RTCM_PARSER_INDEX: - ptrUM980->debugPrintf("Valid RTCM message: 0x%04x (%d) bytes", - parse->length, parse->length); - break; + case UM980_RTCM_PARSER_INDEX: + ptrUM980->debugPrintf("Valid RTCM message: 0x%04x (%d) bytes", parse->length, parse->length); + break; - case UM980_UNICORE_BINARY_PARSER_INDEX: - ptrUM980->debugPrintf("Valid Unicore message: 0x%04x (%d) bytes", - parse->length, parse->length); - break; + case UM980_UNICORE_BINARY_PARSER_INDEX: + ptrUM980->debugPrintf("Valid Unicore message: 0x%04x (%d) bytes", parse->length, parse->length); + break; } } @@ -456,62 +456,59 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) // Process the message switch (type) { - case UM980_UNICORE_BINARY_PARSER_INDEX: - ptrUM980->unicoreHandler(parse->buffer, parse->length); - break; + case UM980_UNICORE_BINARY_PARSER_INDEX: + ptrUM980->unicoreHandler(parse->buffer, parse->length); + break; - case UM980_RTCM_PARSER_INDEX: - break; + case UM980_RTCM_PARSER_INDEX: + break; - case UM980_UNICORE_HASH_PARSER_INDEX: + case UM980_UNICORE_HASH_PARSER_INDEX: + // Does this response contain the command we are looking for? + if (strcasecmp((char *)scratchPad->unicoreHash.sentenceName, ptrUM980->commandName) == 0) // Found + { + ptrUM980->debugPrintf("UM980: Query response: %s", parse->buffer); + ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_OK; + } + break; + + case UM980_NMEA_PARSER_INDEX: + //$command,MODE,response: OK*5D + if (strcasecmp((char *)scratchPad->nmea.sentenceName, "command") != 0 && + strcasecmp((char *)scratchPad->nmea.sentenceName, "MASK") != 0 && + strcasecmp((char *)scratchPad->nmea.sentenceName, "CONFIG") != 0) // Found + + // Unknown response, ignore this message + ptrUM980->debugPrintf("UM980: Message ignored: %s", parse->buffer); + else + { // Does this response contain the command we are looking for? - if (strcasecmp((char *)scratchPad->unicoreHash.sentenceName, ptrUM980->commandName) == 0) // Found + // It may be anywhere in the response: + // $command,MODE,response: OK*5D + char *responsePointer = strcasestr((char *)parse->buffer, ptrUM980->commandName); + if (responsePointer != nullptr) // Found { - ptrUM980->debugPrintf("UM980: Query response: %s", - parse->buffer); - ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_OK; - } - break; + // Display the command response + ptrUM980->debugPrintf("UM980: Command response: %s", parse->buffer); - case UM980_NMEA_PARSER_INDEX: - //$command,MODE,response: OK*5D - if (strcasecmp((char *)scratchPad->nmea.sentenceName, "command") != 0 && - strcasecmp((char *)scratchPad->nmea.sentenceName, "MASK") != 0 && - strcasecmp((char *)scratchPad->nmea.sentenceName, "CONFIG") != 0) // Found - - // Unknown response, ignore this message - ptrUM980->debugPrintf("UM980: Message ignored: %s", parse->buffer); - else - { - // Does this response contain the command we are looking for? - // It may be anywhere in the response: - // $command,MODE,response: OK*5D - char *responsePointer = strcasestr((char *)parse->buffer, ptrUM980->commandName); + // Check to see if we got a command response + responsePointer = strcasestr((char *)parse->buffer, "OK"); if (responsePointer != nullptr) // Found { - // Display the command response - ptrUM980->debugPrintf("UM980: Command response: %s", - parse->buffer); - - // Check to see if we got a command response - responsePointer = strcasestr((char *)parse->buffer, "OK"); - if (responsePointer != nullptr) // Found - { - ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_OK; - return; - } - - responsePointer = strcasestr((char *)parse->buffer, "PARSING"); - if (responsePointer != nullptr) // Found - { - ptrUM980->debugPrintf("UM980: Error response: %s", - parse->buffer); - ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_ERROR; - return; - } + ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_OK; + return; + } + + responsePointer = strcasestr((char *)parse->buffer, "PARSING"); + if (responsePointer != nullptr) // Found + { + ptrUM980->debugPrintf("UM980: Error response: %s", parse->buffer); + ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_ERROR; + return; } } - break; + } + break; } } @@ -966,6 +963,8 @@ Um980Result UM980::sendQuery(const char *command, uint16_t maxWaitMs) strncpy(commandName, command, sizeof(commandName)); commandResponse = UM980_RESULT_RESPONSE_COMMAND_WAITING; // Reset + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Feed the parser until we see a response to the command int wait = 0; while (1) @@ -973,6 +972,7 @@ Um980Result UM980::sendQuery(const char *command, uint16_t maxWaitMs) if (wait++ == maxWaitMs) { debugPrintf("UM980: Response timeout"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -987,12 +987,15 @@ Um980Result UM980::sendQuery(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { debugPrintf("UM980: Query failure"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } delay(1); } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (UM980_RESULT_OK); } @@ -1010,6 +1013,8 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) strncpy(commandName, command, sizeof(commandName)); // Copy to class so that parsers can see it commandResponse = UM980_RESULT_RESPONSE_COMMAND_WAITING; // Reset + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + serialPrintln(command); // Feed the parser until we see a response to the command @@ -1039,6 +1044,8 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) delay(1); } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (UM980_RESULT_OK); } diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.h b/src/SparkFun_Unicore_GNSS_Arduino_Library.h index 4971c51..ab73aae 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.h +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.h @@ -48,81 +48,81 @@ typedef enum UM980_RESULT_RESPONSE_COMMAND_WAITING, } Um980Result; -#define um980BinarySyncA ((uint8_t)0xAA) -#define um980BinarySyncB ((uint8_t)0x44) -#define um980BinarySyncC ((uint8_t)0xB5) -#define um980ASCIISyncEnd ((uint8_t)'\n') - -#define um980HeaderLength ((uint16_t)24) -#define offsetHeaderSyncA ((uint16_t)0) -#define offsetHeaderSyncB ((uint16_t)1) -#define offsetHeaderSyncC ((uint16_t)2) -#define offsetHeaderCpuIdle ((uint16_t)3) -#define offsetHeaderMessageId ((uint16_t)4) -#define offsetHeaderMessageLength ((uint16_t)6) -#define offsetHeaderReferenceTime ((uint16_t)8) -#define offsetHeaderTimeStatus ((uint16_t)9) -#define offsetHeaderWeekNumber ((uint16_t)10) -#define offsetHeaderSecondsOfWeek ((uint16_t)12) -#define offsetHeaderReleaseVersion ((uint16_t)20) -#define offsetHeaderLeapSecond ((uint16_t)21) -#define offsetHeaderOutputDelay ((uint16_t)22) +#define um980BinarySyncA ((uint8_t)0xAA) +#define um980BinarySyncB ((uint8_t)0x44) +#define um980BinarySyncC ((uint8_t)0xB5) +#define um980ASCIISyncEnd ((uint8_t)'\n') + +#define um980HeaderLength ((uint16_t)24) +#define offsetHeaderSyncA ((uint16_t)0) +#define offsetHeaderSyncB ((uint16_t)1) +#define offsetHeaderSyncC ((uint16_t)2) +#define offsetHeaderCpuIdle ((uint16_t)3) +#define offsetHeaderMessageId ((uint16_t)4) +#define offsetHeaderMessageLength ((uint16_t)6) +#define offsetHeaderReferenceTime ((uint16_t)8) +#define offsetHeaderTimeStatus ((uint16_t)9) +#define offsetHeaderWeekNumber ((uint16_t)10) +#define offsetHeaderSecondsOfWeek ((uint16_t)12) +#define offsetHeaderReleaseVersion ((uint16_t)20) +#define offsetHeaderLeapSecond ((uint16_t)21) +#define offsetHeaderOutputDelay ((uint16_t)22) // VERSIONB -#define messageIdVersion ((uint16_t)37) -#define offsetVersionModuleType ((uint16_t)0) +#define messageIdVersion ((uint16_t)37) +#define offsetVersionModuleType ((uint16_t)0) #define offsetVersionFirmwareVersion ((uint16_t)4) -#define offsetVersionAuth ((uint16_t)37) -#define offsetVersionPsn ((uint16_t)166) -#define offsetVersionEfuseID ((uint16_t)232) -#define offsetVersionCompTime ((uint16_t)265) +#define offsetVersionAuth ((uint16_t)37) +#define offsetVersionPsn ((uint16_t)166) +#define offsetVersionEfuseID ((uint16_t)232) +#define offsetVersionCompTime ((uint16_t)265) // BESTNAVB contains HPA, sats tracked/used, lat/long, RTK status, fix status -#define messageIdBestnav ((uint16_t)2118) -#define offsetBestnavPsolStatus ((uint16_t)0) -#define offsetBestnavPosType ((uint16_t)4) -#define offsetBestnavLat ((uint16_t)8) -#define offsetBestnavLon ((uint16_t)16) -#define offsetBestnavHgt ((uint16_t)24) -#define offsetBestnavLatDeviation ((uint16_t)40) -#define offsetBestnavLonDeviation ((uint16_t)44) -#define offsetBestnavHgtDeviation ((uint16_t)48) -#define offsetBestnavSatsTracked ((uint16_t)64) -#define offsetBestnavSatsUsed ((uint16_t)65) -#define offsetBestnavExtSolStat ((uint16_t)69) -#define offsetBestnavVelType ((uint16_t)76) -#define offsetBestnavHorSpd ((uint16_t)88) -#define offsetBestnavTrkGnd ((uint16_t)96) -#define offsetBestnavVertSpd ((uint16_t)104) -#define offsetBestnavVerspdStd ((uint16_t)112) -#define offsetBestnavHorspdStd ((uint16_t)116) +#define messageIdBestnav ((uint16_t)2118) +#define offsetBestnavPsolStatus ((uint16_t)0) +#define offsetBestnavPosType ((uint16_t)4) +#define offsetBestnavLat ((uint16_t)8) +#define offsetBestnavLon ((uint16_t)16) +#define offsetBestnavHgt ((uint16_t)24) +#define offsetBestnavLatDeviation ((uint16_t)40) +#define offsetBestnavLonDeviation ((uint16_t)44) +#define offsetBestnavHgtDeviation ((uint16_t)48) +#define offsetBestnavSatsTracked ((uint16_t)64) +#define offsetBestnavSatsUsed ((uint16_t)65) +#define offsetBestnavExtSolStat ((uint16_t)69) +#define offsetBestnavVelType ((uint16_t)76) +#define offsetBestnavHorSpd ((uint16_t)88) +#define offsetBestnavTrkGnd ((uint16_t)96) +#define offsetBestnavVertSpd ((uint16_t)104) +#define offsetBestnavVerspdStd ((uint16_t)112) +#define offsetBestnavHorspdStd ((uint16_t)116) // BESTNAVXYZB -#define messageIdBestnavXyz ((uint16_t)240) -#define offsetBestnavXyzPsolStatus ((uint16_t)0) -#define offsetBestnavXyzPosType ((uint16_t)4) -#define offsetBestnavXyzPX ((uint16_t)8) -#define offsetBestnavXyzPY ((uint16_t)16) -#define offsetBestnavXyzPZ ((uint16_t)24) +#define messageIdBestnavXyz ((uint16_t)240) +#define offsetBestnavXyzPsolStatus ((uint16_t)0) +#define offsetBestnavXyzPosType ((uint16_t)4) +#define offsetBestnavXyzPX ((uint16_t)8) +#define offsetBestnavXyzPY ((uint16_t)16) +#define offsetBestnavXyzPZ ((uint16_t)24) #define offsetBestnavXyzPXDeviation ((uint16_t)32) #define offsetBestnavXyzPYDeviation ((uint16_t)36) #define offsetBestnavXyzPZDeviation ((uint16_t)40) #define offsetBestnavXyzSatsTracked ((uint16_t)104) -#define offsetBestnavXyzSatsUsed ((uint16_t)105) -#define offsetBestnavXyzExtSolStat ((uint16_t)109) +#define offsetBestnavXyzSatsUsed ((uint16_t)105) +#define offsetBestnavXyzExtSolStat ((uint16_t)109) // RECTIMEB for time/date -#define messageIdRectime ((uint16_t)102) -#define offsetRectimeClockStatus ((uint16_t)0) -#define offsetRectimeOffset ((uint16_t)4) -#define offsetRectimeOffsetStd ((uint16_t)12) -#define offsetRectimeUtcYear ((uint16_t)28) -#define offsetRectimeUtcMonth ((uint16_t)32) -#define offsetRectimeUtcDay ((uint16_t)33) -#define offsetRectimeUtcHour ((uint16_t)34) -#define offsetRectimeUtcMinute ((uint16_t)35) +#define messageIdRectime ((uint16_t)102) +#define offsetRectimeClockStatus ((uint16_t)0) +#define offsetRectimeOffset ((uint16_t)4) +#define offsetRectimeOffsetStd ((uint16_t)12) +#define offsetRectimeUtcYear ((uint16_t)28) +#define offsetRectimeUtcMonth ((uint16_t)32) +#define offsetRectimeUtcDay ((uint16_t)33) +#define offsetRectimeUtcHour ((uint16_t)34) +#define offsetRectimeUtcMinute ((uint16_t)35) #define offsetRectimeUtcMillisecond ((uint16_t)36) -#define offsetRectimeUtcStatus ((uint16_t)40) +#define offsetRectimeUtcStatus ((uint16_t)40) // HWSTATUS has temperature info, and voltage info @@ -149,17 +149,21 @@ class UM980 SEMP_PARSE_STATE *_sempParse; // State of the SparkFun Extensible Message Parser + bool unicoreLibrarySemaphoreBlock = false; // Gets set to true when the Unicore library needs to interact directly with the + // serial hardware + protected: HardwareSerial *_hwSerialPort = nullptr; public: - bool _printBadChecksum = false; // Display bad checksum message from the parser + bool _printBadChecksum = false; // Display bad checksum message from the parser bool _printParserTransitions = false; // Display the parser transitions - bool _printRxMessages = false; // Display the received message summary - bool _dumpRxMessages = false; // Display the received message hex dump + bool _printRxMessages = false; // Display the received message summary + bool _dumpRxMessages = false; // Display the received message hex dump bool begin(HardwareSerial &serialPort, Print *parserDebug = nullptr, Print *parserError = &Serial); bool isConnected(); + bool isBlocking(); bool update(); bool updateOnce(); From 91aff200ee6c53ffe8631a8610db3de89b3426a1 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 11:04:32 -0700 Subject: [PATCH 02/11] Change debug prints --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index f5b07ac..6c53604 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -152,7 +152,7 @@ bool badNmeaChecksum(SEMP_PARSE_STATE *parse) // Display bad checksums if ((!badChecksum) && ptrUM980->_printBadChecksum) { - ptrUM980->debugPrintf("UM980: Message improperly includes %c in checksum", parse->buffer[0]); + ptrUM980->debugPrintf("Unicore Lib: Message improperly includes %c in checksum", parse->buffer[0]); ptrUM980->dumpBuffer(parse->buffer, parse->length); } return badChecksum; @@ -227,7 +227,7 @@ bool UM980::begin(HardwareSerial &serialPort, Print *parserDebug, Print *parserE "SFE_Unicore_GNSS_Library", parserError, parserDebug, badNmeaChecksum); if (!_sempParse) { - debugPrintf("UM980: Failed to initialize the parser!"); + debugPrintf("Unicore Lib: Failed to initialize the parser!"); return false; } @@ -335,7 +335,7 @@ bool UM980::updateOnce() endName = um980GetStateName(_sempParse); // Display the parser state transition - debugPrintf("UM980: 0x%02x (%c), crc: 0x%08x, state: %s --> %s", incoming, + debugPrintf("Unicore Lib: 0x%02x (%c), crc: 0x%08x, state: %s --> %s", incoming, ((incoming >= ' ') && (incoming < 0x7f)) ? incoming : '.', _sempParse->crc, startName, endName); } return (true); @@ -430,21 +430,21 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) switch (type) { case UM980_NMEA_PARSER_INDEX: - ptrUM980->debugPrintf("Valid NMEA Sentence: %s, 0x%04x (%d) bytes", sempNmeaGetSentenceName(parse), + ptrUM980->debugPrintf("Unicore Lib: Valid NMEA Sentence: %s, 0x%04x (%d) bytes", sempNmeaGetSentenceName(parse), parse->length, parse->length); break; case UM980_UNICORE_HASH_PARSER_INDEX: - ptrUM980->debugPrintf("Valid Unicore Hash (#) Sentence: %s, 0x%04x (%d) bytes", + ptrUM980->debugPrintf("Unicore Lib: Valid Unicore Hash (#) Sentence: %s, 0x%04x (%d) bytes", sempUnicoreHashGetSentenceName(parse), parse->length, parse->length); break; case UM980_RTCM_PARSER_INDEX: - ptrUM980->debugPrintf("Valid RTCM message: 0x%04x (%d) bytes", parse->length, parse->length); + ptrUM980->debugPrintf("Unicore Lib: Valid RTCM message: 0x%04x (%d) bytes", parse->length, parse->length); break; case UM980_UNICORE_BINARY_PARSER_INDEX: - ptrUM980->debugPrintf("Valid Unicore message: 0x%04x (%d) bytes", parse->length, parse->length); + ptrUM980->debugPrintf("Unicore Lib: Valid Unicore message: 0x%04x (%d) bytes", parse->length, parse->length); break; } } @@ -467,7 +467,7 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) // Does this response contain the command we are looking for? if (strcasecmp((char *)scratchPad->unicoreHash.sentenceName, ptrUM980->commandName) == 0) // Found { - ptrUM980->debugPrintf("UM980: Query response: %s", parse->buffer); + ptrUM980->debugPrintf("Unicore Lib: Query response: %s", parse->buffer); ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_OK; } break; @@ -479,7 +479,7 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) strcasecmp((char *)scratchPad->nmea.sentenceName, "CONFIG") != 0) // Found // Unknown response, ignore this message - ptrUM980->debugPrintf("UM980: Message ignored: %s", parse->buffer); + ptrUM980->debugPrintf("Unicore Lib: Message ignored: %s", parse->buffer); else { // Does this response contain the command we are looking for? @@ -489,7 +489,7 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) if (responsePointer != nullptr) // Found { // Display the command response - ptrUM980->debugPrintf("UM980: Command response: %s", parse->buffer); + ptrUM980->debugPrintf("Unicore Lib: Known command response: %s", parse->buffer); // Check to see if we got a command response responsePointer = strcasestr((char *)parse->buffer, "OK"); @@ -502,11 +502,17 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) responsePointer = strcasestr((char *)parse->buffer, "PARSING"); if (responsePointer != nullptr) // Found { - ptrUM980->debugPrintf("UM980: Error response: %s", parse->buffer); + ptrUM980->debugPrintf("Unicore Lib: Error response: %s", parse->buffer); ptrUM980->commandResponse = UM980_RESULT_RESPONSE_COMMAND_ERROR; return; } } + else + { + // Display the command response + ptrUM980->debugPrintf("Unicore Lib: Unknown command response: %s", parse->buffer); + ptrUM980->debugPrintf("Unicore Lib: Looking for command: %s", ptrUM980->commandName); + } } break; } @@ -971,7 +977,7 @@ Um980Result UM980::sendQuery(const char *command, uint16_t maxWaitMs) { if (wait++ == maxWaitMs) { - debugPrintf("UM980: Response timeout"); + debugPrintf("Unicore Lib: Response timeout"); unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -980,13 +986,13 @@ Um980Result UM980::sendQuery(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_OK) { - debugPrintf("UM980: Response received"); + debugPrintf("Unicore Lib: Response received"); break; } if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { - debugPrintf("UM980: Query failure"); + debugPrintf("Unicore Lib: Query failure"); unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } @@ -1009,7 +1015,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) { clearBuffer(); - debugPrintf("UM980: Sending command %s", command); + debugPrintf("Unicore Lib: Sending command %s", command); strncpy(commandName, command, sizeof(commandName)); // Copy to class so that parsers can see it commandResponse = UM980_RESULT_RESPONSE_COMMAND_WAITING; // Reset @@ -1023,7 +1029,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) { if (wait++ == maxWaitMs) { - debugPrintf("UM980: Command timeout"); + debugPrintf("Unicore Lib: Command timeout"); return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -1031,13 +1037,13 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_OK) { - debugPrintf("UM980: Command success"); + debugPrintf("Unicore Lib: Command success"); break; } if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { - debugPrintf("UM980: Command error"); + debugPrintf("Unicore Lib: Command error"); return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } From a68f37e2c0fd75d6401c044867297f8a624daea9 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 11:04:42 -0700 Subject: [PATCH 03/11] Increase buffer to prevent overflow --- src/SparkFun_Unicore_GNSS_Arduino_Library.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.h b/src/SparkFun_Unicore_GNSS_Arduino_Library.h index ab73aae..9eeb275 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.h +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.h @@ -188,7 +188,7 @@ class UM980 void dumpBuffer(const uint8_t *buffer, uint16_t length); - char commandName[20] = ""; // Passes the command type into parser + char commandName[40] = ""; // Passes the command type into parser - MODE ROVER AUTOMOTIVE uint8_t commandResponse = UM980_RESULT_OK; // Gets EOM result from parser // Mode From 0fdd0c349e44d718cfd9e4fca5c09c4cc8ed3183 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 14:17:53 -0700 Subject: [PATCH 04/11] Add fix check based on NMEA before starting binary --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 116 ++++++++++++++++-- src/SparkFun_Unicore_GNSS_Arduino_Library.h | 14 ++- 2 files changed, 119 insertions(+), 11 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index 6c53604..56e2728 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -278,7 +278,7 @@ bool UM980::isConnected() // If isBlocking is true, external consumers should not read/write to the Serial hardware bool UM980::isBlocking() { - return(unicoreLibrarySemaphoreBlock); + return (unicoreLibrarySemaphoreBlock); } // Calling this function with nothing sets the debug port to Serial @@ -430,8 +430,8 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) switch (type) { case UM980_NMEA_PARSER_INDEX: - ptrUM980->debugPrintf("Unicore Lib: Valid NMEA Sentence: %s, 0x%04x (%d) bytes", sempNmeaGetSentenceName(parse), - parse->length, parse->length); + ptrUM980->debugPrintf("Unicore Lib: Valid NMEA Sentence: %s, 0x%04x (%d) bytes", + sempNmeaGetSentenceName(parse), parse->length, parse->length); break; case UM980_UNICORE_HASH_PARSER_INDEX: @@ -444,7 +444,8 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) break; case UM980_UNICORE_BINARY_PARSER_INDEX: - ptrUM980->debugPrintf("Unicore Lib: Valid Unicore message: 0x%04x (%d) bytes", parse->length, parse->length); + ptrUM980->debugPrintf("Unicore Lib: Valid Unicore message: 0x%04x (%d) bytes", parse->length, + parse->length); break; } } @@ -473,13 +474,23 @@ void um980ProcessMessage(SEMP_PARSE_STATE *parse, uint16_t type) break; case UM980_NMEA_PARSER_INDEX: - //$command,MODE,response: OK*5D + + // Is this a NMEA response or command response? + if (strcasecmp((char *)scratchPad->nmea.sentenceName, "command") != 0 && strcasecmp((char *)scratchPad->nmea.sentenceName, "MASK") != 0 && - strcasecmp((char *)scratchPad->nmea.sentenceName, "CONFIG") != 0) // Found + strcasecmp((char *)scratchPad->nmea.sentenceName, "CONFIG") != 0) + { + // command, MASK, CONFIG not found + + if (strcasecmp((char *)scratchPad->nmea.sentenceName, "GNGGA") == 0) + { + ptrUM980->debugPrintf("um980ProcessMessage GNGGA"); + } // Unknown response, ignore this message ptrUM980->debugPrintf("Unicore Lib: Message ignored: %s", parse->buffer); + } else { // Does this response contain the command we are looking for? @@ -1154,7 +1165,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) } else if (messageID == messageIdBestnavXyz) { - // debugPrintf("BestNavXyz Handler"); + debugPrintf("BestNavXyz Handler"); CHECK_POINTER_VOID(packetBESTNAVXYZ, initBestnavXyz); // Check that RAM has been allocated lastUpdateEcef = millis(); // Update stale marker @@ -1172,7 +1183,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) } else if (messageID == messageIdVersion) { - // debugPrintf("Version Handler"); + debugPrintf("Version Handler"); CHECK_POINTER_VOID(packetVERSION, initVersion); // Check that RAM has been allocated lastUpdateVersion = millis(); // Update stale marker @@ -1188,7 +1199,48 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) } else { - debugPrintf("Unknown message id: %d\r\n", messageID); + // Is this a NMEA sentence? + if (response[0] == '$') + { + response[length] = '\0'; // Force terminator because strncasestr does not exist + + // The UM980 does not respond to binary requests when there is no GNSS reception. + // Block BestNavB, etc commands if there is no fix. + // Look for GNGGA NMEA then extract GNSS position status (spot 6). + // $GNGGA,181535.00,,,,,0,00,9999.0,,,,,,*43 + char *responsePointer = strcasestr((char *)response, "GNGGA"); + if (responsePointer != nullptr) // Found + { + char gngga[100]; + strncpy(gngga, (const char *)response, length); // Make copy before strtok + + debugPrintf("Unicore Lib: GNGGA message: %s\r\n", gngga); + + char *pt; + pt = strtok(gngga, ","); + int counter = 0; + while (pt != NULL) + { + int spotValue = atoi(pt); + // Serial.printf("counter: %d spot: %s spotvalue: %d\r\n", counter, pt, spotValue); + if (counter++ == 6) + { + nmeaPositionStatus = spotValue; + debugPrintf("nmeaPositionStatus: %d\r\n", nmeaPositionStatus); + } + pt = strtok(NULL, ","); + } + } + else + { + // Unhandled NMEA message + // debugPrintf("Unicore Lib: Unhandled NMEA sentence (%d bytes): %s\r\n", length, (char *)response); + } + } + else + { + debugPrintf("Unicore Lib: Unknown message id: %d\r\n", messageID); + } } } @@ -1238,6 +1290,19 @@ bool UM980::initVersion() // Allocate RAM for packetBESTNAV and initialize it bool UM980::initBestnav(uint8_t rate) { + if ((startBinaryBeforeFix == false) && (isNmeaFixed() == false)) + { + debugPrintf("Unicore Lib: BestNav no fix"); + return (false); + } + else + { + if(startBinaryBeforeFix == true) + Serial.println("startBinaryBeforeFix is true"); + if(isNmeaFixed() == true) + Serial.println("isNmeaFixed() is true"); + } + packetBESTNAV = new UNICORE_BESTNAV_t; // Allocate RAM for the main struct if (packetBESTNAV == nullptr) { @@ -1283,6 +1348,12 @@ bool UM980::initBestnav(uint8_t rate) // Allocate RAM for packetBESTNAVXYZ and initialize it bool UM980::initBestnavXyz(uint8_t rate) { + if ((startBinaryBeforeFix == false) && (isNmeaFixed() == false)) + { + debugPrintf("Unicore Lib: BestNavXyz no fix"); + return (false); + } + packetBESTNAVXYZ = new UNICORE_BESTNAVXYZ_t; // Allocate RAM for the main struct if (packetBESTNAVXYZ == nullptr) { @@ -1328,6 +1399,12 @@ bool UM980::initBestnavXyz(uint8_t rate) // Allocate RAM for packetRECTIME and initialize it bool UM980::initRectime(uint8_t rate) { + if ((startBinaryBeforeFix == false) && (isNmeaFixed() == false)) + { + debugPrintf("Unicore Lib: RecTime no fix"); + return (false); + } + packetRECTIME = new UNICORE_RECTIME_t; // Allocate RAM for the main struct if (packetRECTIME == nullptr) { @@ -1618,3 +1695,24 @@ char *UM980::getVersionFull(uint16_t maxWaitMs) return ((char *)"Error1"); return ((char *)"Error2"); } + +// Returns true when GNGGA NMEA reports position status >= 2 +bool UM980::isNmeaFixed() +{ + if (nmeaPositionStatus >= 2) + return (true); + return (false); +} + +// By default, library will attempt to start RECTIME and BESTNAV regardless of GNSS fix +// This may lead to command timeouts as the UM980 does not appear to respond to BESTNAVB commands if 3D fix is not +// achieved. Set startBinartBeforeFix = false via disableBinaryBeforeFix() to block binary commands before a fix is +// achieved +void UM980::enableBinaryBeforeFix() +{ + startBinaryBeforeFix = true; +} +void UM980::disableBinaryBeforeFix() +{ + startBinaryBeforeFix = false; +} diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.h b/src/SparkFun_Unicore_GNSS_Arduino_Library.h index 9eeb275..51e6f58 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.h +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.h @@ -137,8 +137,8 @@ class UM980 unsigned long lastUpdateDateTime = 0; unsigned long lastUpdateVersion = 0; - bool staleDateTime(); - bool staleEcef(); + bool isNmeaFixed(); // Returns true when GNGGA NMEA reports position status >= 2 + void stopAutoReports(); // Delete all pointers to force reinit next time a helper function is called Um980Result getGeodetic(uint16_t maxWaitMs = 1500); @@ -161,6 +161,13 @@ class UM980 bool _printRxMessages = false; // Display the received message summary bool _dumpRxMessages = false; // Display the received message hex dump + uint8_t nmeaPositionStatus = 0; // Position psition status obtained from GNGGA NMEA + + // By default, library will attempt to start RECTIME and BESTNAV regardless of GNSS fix. + // This may lead to command timeouts as the UM980 does not appear to respond to BESTNAVB commands if 3D fix is not achieved. + // Set startBinartBeforeFix = false via disableBinaryBeforeFix() to block binary commands before a fix is achieved + bool startBinaryBeforeFix = true; + bool begin(HardwareSerial &serialPort, Print *parserDebug = nullptr, Print *parserError = &Serial); bool isConnected(); bool isBlocking(); @@ -176,6 +183,9 @@ class UM980 void enableParserErrors(Print *print = &Serial); void disableParserErrors(); + void enableBinaryBeforeFix(); + void disableBinaryBeforeFix(); + void enablePrintBadChecksums(); void disablePrintBadChecksums(); void enablePrintParserTransitions(); From 992fe16d9a06fd83c854746f7d377822127736a0 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 14:19:51 -0700 Subject: [PATCH 05/11] Add blocking during Inits --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index 56e2728..99a2d20 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -1266,6 +1266,8 @@ bool UM980::initVersion() debugPrintf("VERSION started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until response is received lastUpdateVersion = 0; uint16_t maxWait = 1000; // Wait for one response to come in @@ -1280,10 +1282,12 @@ bool UM980::initVersion() debugPrintf("GNSS: Failed to get response from VERSION start"); delete packetVERSION; packetVERSION = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1297,10 +1301,10 @@ bool UM980::initBestnav(uint8_t rate) } else { - if(startBinaryBeforeFix == true) + if (startBinaryBeforeFix == true) Serial.println("startBinaryBeforeFix is true"); - if(isNmeaFixed() == true) - Serial.println("isNmeaFixed() is true"); + if (isNmeaFixed() == true) + Serial.println("isNmeaFixed() is true"); } packetBESTNAV = new UNICORE_BESTNAV_t; // Allocate RAM for the main struct @@ -1324,6 +1328,8 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("BestNav started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until first report is available lastUpdateGeodetic = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1338,10 +1344,12 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNav start"); delete packetBESTNAV; packetBESTNAV = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1375,6 +1383,8 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("BestNavXYZB started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until first report is available lastUpdateEcef = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1389,10 +1399,13 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNavXyz start"); delete packetBESTNAVXYZ; packetBESTNAVXYZ = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (true); } @@ -1428,6 +1441,8 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("RecTimeB started"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + // Wait until first report is available lastUpdateDateTime = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1442,10 +1457,13 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("GNSS: Failed to get response from RecTime start"); delete packetRECTIME; packetRECTIME = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (true); } From e663e95b40c86205038e85a24022e8f1e7d34283 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 14:44:04 -0700 Subject: [PATCH 06/11] Fix position status at 1 --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 5 +++-- src/SparkFun_Unicore_GNSS_Arduino_Library.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index 99a2d20..bfc7fee 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -1714,10 +1714,10 @@ char *UM980::getVersionFull(uint16_t maxWaitMs) return ((char *)"Error2"); } -// Returns true when GNGGA NMEA reports position status >= 2 +// Returns true when GNGGA NMEA reports position status >= 1 bool UM980::isNmeaFixed() { - if (nmeaPositionStatus >= 2) + if (nmeaPositionStatus >= 1) return (true); return (false); } @@ -1733,4 +1733,5 @@ void UM980::enableBinaryBeforeFix() void UM980::disableBinaryBeforeFix() { startBinaryBeforeFix = false; + Serial.println("\r\n Setting sbbf to false\r\n"); } diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.h b/src/SparkFun_Unicore_GNSS_Arduino_Library.h index 51e6f58..36788d5 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.h +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.h @@ -137,7 +137,7 @@ class UM980 unsigned long lastUpdateDateTime = 0; unsigned long lastUpdateVersion = 0; - bool isNmeaFixed(); // Returns true when GNGGA NMEA reports position status >= 2 + bool isNmeaFixed(); // Returns true when GNGGA NMEA reports position status >= 1 void stopAutoReports(); // Delete all pointers to force reinit next time a helper function is called From 3e89677702767b7035618659e77d388f924f5961 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 14:49:25 -0700 Subject: [PATCH 07/11] Fix incorrect block. Remove extraneous prints. --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index bfc7fee..ce06f5d 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -1222,12 +1222,8 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) while (pt != NULL) { int spotValue = atoi(pt); - // Serial.printf("counter: %d spot: %s spotvalue: %d\r\n", counter, pt, spotValue); if (counter++ == 6) - { nmeaPositionStatus = spotValue; - debugPrintf("nmeaPositionStatus: %d\r\n", nmeaPositionStatus); - } pt = strtok(NULL, ","); } } @@ -1299,13 +1295,6 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("Unicore Lib: BestNav no fix"); return (false); } - else - { - if (startBinaryBeforeFix == true) - Serial.println("startBinaryBeforeFix is true"); - if (isNmeaFixed() == true) - Serial.println("isNmeaFixed() is true"); - } packetBESTNAV = new UNICORE_BESTNAV_t; // Allocate RAM for the main struct if (packetBESTNAV == nullptr) @@ -1441,7 +1430,7 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("RecTimeB started"); - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware // Wait until first report is available lastUpdateDateTime = 0; @@ -1733,5 +1722,4 @@ void UM980::enableBinaryBeforeFix() void UM980::disableBinaryBeforeFix() { startBinaryBeforeFix = false; - Serial.println("\r\n Setting sbbf to false\r\n"); } From c0a92de5ff028e2df1550cf98db1fdab52bd4bf7 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 27 Feb 2024 15:17:30 -0700 Subject: [PATCH 08/11] Consolidate and fix blocking --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index ce06f5d..9355402 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -296,8 +296,14 @@ void UM980::disableDebugging() bool UM980::update() { bool newData = false; + + unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware + while (serialAvailable()) newData = updateOnce(); + + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (newData); } @@ -1041,6 +1047,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (wait++ == maxWaitMs) { debugPrintf("Unicore Lib: Command timeout"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -1055,6 +1062,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { debugPrintf("Unicore Lib: Command error"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } @@ -1137,6 +1145,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) memcpy(&extSolStat, &data[offsetBestnavExtSolStat], sizeof(uint8_t)); packetBESTNAV->data.rtkSolution = extSolStat & 0x01; // 0 = unchecked, 1 = checked packetBESTNAV->data.pseudorangeCorrection = (extSolStat >> 1) & 0b111; // Limit to three bits + debugPrintf("BestNav Handler 2"); } else if (messageID == messageIdRectime) { @@ -1212,7 +1221,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) if (responsePointer != nullptr) // Found { char gngga[100]; - strncpy(gngga, (const char *)response, length); // Make copy before strtok + strncpy(gngga, (const char *)response, length - 1); // Make copy before strtok debugPrintf("Unicore Lib: GNGGA message: %s\r\n", gngga); @@ -1262,8 +1271,6 @@ bool UM980::initVersion() debugPrintf("VERSION started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until response is received lastUpdateVersion = 0; uint16_t maxWait = 1000; // Wait for one response to come in @@ -1278,12 +1285,10 @@ bool UM980::initVersion() debugPrintf("GNSS: Failed to get response from VERSION start"); delete packetVERSION; packetVERSION = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1317,8 +1322,6 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("BestNav started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until first report is available lastUpdateGeodetic = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1333,12 +1336,10 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNav start"); delete packetBESTNAV; packetBESTNAV = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1372,8 +1373,6 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("BestNavXYZB started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until first report is available lastUpdateEcef = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1388,13 +1387,10 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNavXyz start"); delete packetBESTNAVXYZ; packetBESTNAVXYZ = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware - return (true); } @@ -1430,8 +1426,6 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("RecTimeB started"); - unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware - // Wait until first report is available lastUpdateDateTime = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1446,13 +1440,10 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("GNSS: Failed to get response from RecTime start"); delete packetRECTIME; packetRECTIME = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware - return (true); } From 939a58f537fbe00c8823c7d8956165eff2d11e40 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 28 Feb 2024 13:00:12 -0700 Subject: [PATCH 09/11] Remove extra debugPrint --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index 9355402..2a206a7 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -1145,7 +1145,6 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) memcpy(&extSolStat, &data[offsetBestnavExtSolStat], sizeof(uint8_t)); packetBESTNAV->data.rtkSolution = extSolStat & 0x01; // 0 = unchecked, 1 = checked packetBESTNAV->data.pseudorangeCorrection = (extSolStat >> 1) & 0b111; // Limit to three bits - debugPrintf("BestNav Handler 2"); } else if (messageID == messageIdRectime) { From 66dd39afeda7d6c85d7ec6750a16de22d988ee36 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 6 Mar 2024 09:15:23 -0700 Subject: [PATCH 10/11] Move blocking into functions that expect a response --- src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index 2a206a7..ce06f5d 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -296,14 +296,8 @@ void UM980::disableDebugging() bool UM980::update() { bool newData = false; - - unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware - while (serialAvailable()) newData = updateOnce(); - - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware - return (newData); } @@ -1047,7 +1041,6 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (wait++ == maxWaitMs) { debugPrintf("Unicore Lib: Command timeout"); - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -1062,7 +1055,6 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { debugPrintf("Unicore Lib: Command error"); - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } @@ -1220,7 +1212,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) if (responsePointer != nullptr) // Found { char gngga[100]; - strncpy(gngga, (const char *)response, length - 1); // Make copy before strtok + strncpy(gngga, (const char *)response, length); // Make copy before strtok debugPrintf("Unicore Lib: GNGGA message: %s\r\n", gngga); @@ -1270,6 +1262,8 @@ bool UM980::initVersion() debugPrintf("VERSION started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until response is received lastUpdateVersion = 0; uint16_t maxWait = 1000; // Wait for one response to come in @@ -1284,10 +1278,12 @@ bool UM980::initVersion() debugPrintf("GNSS: Failed to get response from VERSION start"); delete packetVERSION; packetVERSION = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1321,6 +1317,8 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("BestNav started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until first report is available lastUpdateGeodetic = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1335,10 +1333,12 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNav start"); delete packetBESTNAV; packetBESTNAV = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1372,6 +1372,8 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("BestNavXYZB started"); + unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data + // Wait until first report is available lastUpdateEcef = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1386,10 +1388,13 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNavXyz start"); delete packetBESTNAVXYZ; packetBESTNAVXYZ = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (true); } @@ -1425,6 +1430,8 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("RecTimeB started"); + unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware + // Wait until first report is available lastUpdateDateTime = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1439,10 +1446,13 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("GNSS: Failed to get response from RecTime start"); delete packetRECTIME; packetRECTIME = nullptr; + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (true); } From 05fc85f9e7bf4fc57fca2c92c63171204c385bab Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 6 Mar 2024 09:19:45 -0700 Subject: [PATCH 11/11] Update keywords --- keywords.txt | 4 +++ src/SparkFun_Unicore_GNSS_Arduino_Library.cpp | 28 ++++++------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/keywords.txt b/keywords.txt index 2463782..823a25b 100644 --- a/keywords.txt +++ b/keywords.txt @@ -15,6 +15,7 @@ Um980Result KEYWORD1 begin KEYWORD2 isConnected KEYWORD2 +isBlocking KEYWORD2 enableDebugging KEYWORD2 disableDebugging KEYWORD2 @@ -110,6 +111,9 @@ getVersion KEYWORD2 getCompileTime KEYWORD2 getVersionFull KEYWORD2 +enableBinaryBeforeFix KEYWORD2 +disableBinaryBeforeFix KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp index ce06f5d..2a206a7 100644 --- a/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_Unicore_GNSS_Arduino_Library.cpp @@ -296,8 +296,14 @@ void UM980::disableDebugging() bool UM980::update() { bool newData = false; + + unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware + while (serialAvailable()) newData = updateOnce(); + + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware + return (newData); } @@ -1041,6 +1047,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (wait++ == maxWaitMs) { debugPrintf("Unicore Lib: Command timeout"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_TIMEOUT_RESPONSE); } @@ -1055,6 +1062,7 @@ Um980Result UM980::sendString(const char *command, uint16_t maxWaitMs) if (commandResponse == UM980_RESULT_RESPONSE_COMMAND_ERROR) { debugPrintf("Unicore Lib: Command error"); + unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (UM980_RESULT_RESPONSE_COMMAND_ERROR); } @@ -1212,7 +1220,7 @@ void UM980::unicoreHandler(uint8_t *response, uint16_t length) if (responsePointer != nullptr) // Found { char gngga[100]; - strncpy(gngga, (const char *)response, length); // Make copy before strtok + strncpy(gngga, (const char *)response, length - 1); // Make copy before strtok debugPrintf("Unicore Lib: GNGGA message: %s\r\n", gngga); @@ -1262,8 +1270,6 @@ bool UM980::initVersion() debugPrintf("VERSION started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until response is received lastUpdateVersion = 0; uint16_t maxWait = 1000; // Wait for one response to come in @@ -1278,12 +1284,10 @@ bool UM980::initVersion() debugPrintf("GNSS: Failed to get response from VERSION start"); delete packetVERSION; packetVERSION = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1317,8 +1321,6 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("BestNav started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until first report is available lastUpdateGeodetic = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1333,12 +1335,10 @@ bool UM980::initBestnav(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNav start"); delete packetBESTNAV; packetBESTNAV = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (true); } @@ -1372,8 +1372,6 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("BestNavXYZB started"); - unicoreLibrarySemaphoreBlock = true; // Prevent external tasks from harvesting serial data - // Wait until first report is available lastUpdateEcef = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1388,13 +1386,10 @@ bool UM980::initBestnavXyz(uint8_t rate) debugPrintf("GNSS: Failed to get response from BestNavXyz start"); delete packetBESTNAVXYZ; packetBESTNAVXYZ = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware - return (true); } @@ -1430,8 +1425,6 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("RecTimeB started"); - unicoreLibrarySemaphoreBlock = true; // Allow external tasks to control serial hardware - // Wait until first report is available lastUpdateDateTime = 0; uint16_t maxWait = (1000 / rate) + 100; // Wait for one response to come in @@ -1446,13 +1439,10 @@ bool UM980::initRectime(uint8_t rate) debugPrintf("GNSS: Failed to get response from RecTime start"); delete packetRECTIME; packetRECTIME = nullptr; - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware return (false); } } - unicoreLibrarySemaphoreBlock = false; // Allow external tasks to control serial hardware - return (true); }