@@ -399,6 +399,16 @@ void DevUBLOXGNSS::end(void)
399399 packetUBXTIMTM2 = nullptr;
400400 }
401401
402+ if (packetUBXTIMTP != nullptr)
403+ {
404+ if (packetUBXTIMTP->callbackData != nullptr)
405+ {
406+ delete packetUBXTIMTP->callbackData;
407+ }
408+ delete packetUBXTIMTP;
409+ packetUBXTIMTP = nullptr;
410+ }
411+
402412#ifndef SFE_UBLOX_DISABLE_ESF
403413 if (packetUBXESFALG != nullptr)
404414 {
@@ -1397,6 +1407,12 @@ bool DevUBLOXGNSS::autoLookup(uint8_t Class, uint8_t ID, uint16_t *maxSize)
13971407 *maxSize = UBX_TIM_TM2_LEN;
13981408 return (packetUBXTIMTM2 != nullptr);
13991409 }
1410+ else if (ID == UBX_TIM_TP)
1411+ {
1412+ if (maxSize != nullptr)
1413+ *maxSize = UBX_TIM_TP_LEN;
1414+ return (packetUBXTIMTP != nullptr);
1415+ }
14001416 break;
14011417 case UBX_CLASS_ESF:
14021418#ifndef SFE_UBLOX_DISABLE_ESF
@@ -4158,6 +4174,36 @@ void DevUBLOXGNSS::processUBXpacket(ubxPacket *msg)
41584174 }
41594175 }
41604176 }
4177+ else if (msg->id == UBX_TIM_TP && msg->len == UBX_TIM_TP_LEN)
4178+ {
4179+ // Parse various byte fields into storage - but only if we have memory allocated for it
4180+ if (packetUBXTIMTP != nullptr)
4181+ {
4182+ packetUBXTIMTP->data.towMS = extractLong(msg, 0);
4183+ packetUBXTIMTP->data.towSubMS = extractLong(msg, 4);
4184+ packetUBXTIMTP->data.qErr = extractSignedLong(msg, 8);
4185+ packetUBXTIMTP->data.week = extractInt(msg, 12);
4186+ packetUBXTIMTP->data.flags.all = extractByte(msg, 14);
4187+ packetUBXTIMTP->data.refInfo.all = extractByte(msg, 15);
4188+
4189+ // Mark all datums as fresh (not read before)
4190+ packetUBXTIMTP->moduleQueried.moduleQueried.all = 0xFFFFFFFF;
4191+
4192+ // Check if we need to copy the data for the callback
4193+ if ((packetUBXTIMTP->callbackData != nullptr) // If RAM has been allocated for the copy of the data
4194+ && (packetUBXTIMTP->automaticFlags.flags.bits.callbackCopyValid == false)) // AND the data is stale
4195+ {
4196+ memcpy(&packetUBXTIMTP->callbackData->towMS, &packetUBXTIMTP->data.towMS, sizeof(UBX_TIM_TP_data_t));
4197+ packetUBXTIMTP->automaticFlags.flags.bits.callbackCopyValid = true;
4198+ }
4199+
4200+ // Check if we need to copy the data into the file buffer
4201+ if (packetUBXTIMTP->automaticFlags.flags.bits.addToFileBuffer)
4202+ {
4203+ addedToFileBuffer = storePacket(msg);
4204+ }
4205+ }
4206+ }
41614207 break;
41624208#ifndef SFE_UBLOX_DISABLE_ESF
41634209 case UBX_CLASS_ESF:
@@ -5642,6 +5688,17 @@ void DevUBLOXGNSS::checkCallbacks(void)
56425688 packetUBXTIMTM2->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
56435689 }
56445690
5691+ if (packetUBXTIMTP != nullptr) // If RAM has been allocated for message storage
5692+ if (packetUBXTIMTP->callbackData != nullptr) // If RAM has been allocated for the copy of the data
5693+ if (packetUBXTIMTP->automaticFlags.flags.bits.callbackCopyValid == true) // If the copy of the data is valid
5694+ {
5695+ if (packetUBXTIMTP->callbackPointerPtr != nullptr) // If the pointer to the callback has been defined
5696+ {
5697+ packetUBXTIMTP->callbackPointerPtr(packetUBXTIMTP->callbackData); // Call the callback
5698+ }
5699+ packetUBXTIMTP->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
5700+ }
5701+
56455702#ifndef SFE_UBLOX_DISABLE_ESF
56465703 if (packetUBXESFALG != nullptr) // If RAM has been allocated for message storage
56475704 if (packetUBXESFALG->callbackData != nullptr) // If RAM has been allocated for the copy of the data
@@ -13010,6 +13067,172 @@ void DevUBLOXGNSS::logTIMTM2(bool enabled)
1301013067 packetUBXTIMTM2->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
1301113068}
1301213069
13070+ // ***** TIM TP automatic support
13071+
13072+ bool DevUBLOXGNSS::getTIMTP(uint16_t maxWait)
13073+ {
13074+ if (packetUBXTIMTP == nullptr)
13075+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the TP data
13076+ if (packetUBXTIMTP == nullptr) // Bail if the RAM allocation failed
13077+ return (false);
13078+
13079+ if (packetUBXTIMTP->automaticFlags.flags.bits.automatic && packetUBXTIMTP->automaticFlags.flags.bits.implicitUpdate)
13080+ {
13081+ // The GPS is automatically reporting, we just check whether we got unread data
13082+ checkUbloxInternal(&packetCfg, 0, 0); // Call checkUbloxInternal to parse any incoming data. Don't overwrite the requested Class and ID
13083+ return packetUBXTIMTP->moduleQueried.moduleQueried.bits.all;
13084+ }
13085+ else if (packetUBXTIMTP->automaticFlags.flags.bits.automatic && !packetUBXTIMTP->automaticFlags.flags.bits.implicitUpdate)
13086+ {
13087+ // Someone else has to call checkUblox for us...
13088+ return (false);
13089+ }
13090+ else
13091+ {
13092+ // The GPS is not automatically reporting navigation position so we have to poll explicitly
13093+ packetCfg.cls = UBX_CLASS_TIM;
13094+ packetCfg.id = UBX_TIM_TP;
13095+ packetCfg.len = 0;
13096+ packetCfg.startingSpot = 0;
13097+
13098+ // The data is parsed as part of processing the response
13099+ sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait);
13100+
13101+ if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED)
13102+ return (true);
13103+
13104+ if (retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN)
13105+ {
13106+ return (true);
13107+ }
13108+
13109+ return (false);
13110+ }
13111+ }
13112+
13113+ // Enable or disable automatic message generation by the GNSS. This changes the way getTIMTP works.
13114+ bool DevUBLOXGNSS::setAutoTIMTP(bool enable, uint8_t layer, uint16_t maxWait)
13115+ {
13116+ return setAutoTIMTPrate(enable ? 1 : 0, true, layer, maxWait);
13117+ }
13118+
13119+ // Enable or disable automatic message generation by the GNSS. This changes the way getTIMTP works.
13120+ bool DevUBLOXGNSS::setAutoTIMTP(bool enable, bool implicitUpdate, uint8_t layer, uint16_t maxWait)
13121+ {
13122+ return setAutoTIMTPrate(enable ? 1 : 0, implicitUpdate, layer, maxWait);
13123+ }
13124+
13125+ // Enable or disable automatic message generation by the GNSS. This changes the way getTIMTP works.
13126+ bool DevUBLOXGNSS::setAutoTIMTPrate(uint8_t rate, bool implicitUpdate, uint8_t layer, uint16_t maxWait)
13127+ {
13128+ if (packetUBXTIMTP == nullptr)
13129+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the data
13130+ if (packetUBXTIMTP == nullptr) // Only attempt this if RAM allocation was successful
13131+ return false;
13132+
13133+ if (rate > 127)
13134+ rate = 127;
13135+
13136+ uint32_t key = UBLOX_CFG_MSGOUT_UBX_TIM_TP_I2C;
13137+ if (_commType == COMM_TYPE_SPI)
13138+ key = UBLOX_CFG_MSGOUT_UBX_TIM_TP_SPI;
13139+ else if (_commType == COMM_TYPE_SERIAL)
13140+ {
13141+ if (!_UART2)
13142+ key = UBLOX_CFG_MSGOUT_UBX_TIM_TP_UART1;
13143+ else
13144+ key = UBLOX_CFG_MSGOUT_UBX_TIM_TP_UART2;
13145+ }
13146+
13147+ bool ok = setVal8(key, rate, layer, maxWait);
13148+ if (ok)
13149+ {
13150+ packetUBXTIMTP->automaticFlags.flags.bits.automatic = (rate > 0);
13151+ packetUBXTIMTP->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
13152+ }
13153+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.all = false;
13154+ return ok;
13155+ }
13156+
13157+ // Enable automatic message generation by the GNSS.
13158+ bool DevUBLOXGNSS::setAutoTIMTPcallbackPtr(void (*callbackPointerPtr)(UBX_TIM_TP_data_t *), uint8_t layer, uint16_t maxWait)
13159+ {
13160+ // Enable auto messages. Set implicitUpdate to false as we expect the user to call checkUblox manually.
13161+ bool result = setAutoTIMTP(true, false, layer, maxWait);
13162+ if (!result)
13163+ return (result); // Bail if setAuto failed
13164+
13165+ if (packetUBXTIMTP->callbackData == nullptr) // Check if RAM has been allocated for the callback copy
13166+ {
13167+ packetUBXTIMTP->callbackData = new UBX_TIM_TP_data_t; // Allocate RAM for the main struct
13168+ }
13169+
13170+ if (packetUBXTIMTP->callbackData == nullptr)
13171+ {
13172+ #ifndef SFE_UBLOX_REDUCED_PROG_MEM
13173+ if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
13174+ _debugSerial.println(F("setAutoTIMTPcallbackPtr: RAM alloc failed!"));
13175+ #endif
13176+ return (false);
13177+ }
13178+
13179+ packetUBXTIMTP->callbackPointerPtr = callbackPointerPtr;
13180+ return (true);
13181+ }
13182+
13183+ // In case no config access to the GNSS is possible and TIM TP is send cyclically already
13184+ // set config to suitable parameters
13185+ bool DevUBLOXGNSS::assumeAutoTIMTP(bool enabled, bool implicitUpdate)
13186+ {
13187+ if (packetUBXTIMTP == nullptr)
13188+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the data
13189+ if (packetUBXTIMTP == nullptr) // Only attempt this if RAM allocation was successful
13190+ return false;
13191+
13192+ bool changes = packetUBXTIMTP->automaticFlags.flags.bits.automatic != enabled || packetUBXTIMTP->automaticFlags.flags.bits.implicitUpdate != implicitUpdate;
13193+ if (changes)
13194+ {
13195+ packetUBXTIMTP->automaticFlags.flags.bits.automatic = enabled;
13196+ packetUBXTIMTP->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
13197+ }
13198+ return changes;
13199+ }
13200+
13201+ // PRIVATE: Allocate RAM for packetUBXTIMTP and initialize it
13202+ bool DevUBLOXGNSS::initPacketUBXTIMTP()
13203+ {
13204+ packetUBXTIMTP = new UBX_TIM_TP_t; // Allocate RAM for the main struct
13205+ if (packetUBXTIMTP == nullptr)
13206+ {
13207+ #ifndef SFE_UBLOX_REDUCED_PROG_MEM
13208+ if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
13209+ _debugSerial.println(F("initPacketUBXTIMTP: RAM alloc failed!"));
13210+ #endif
13211+ return (false);
13212+ }
13213+ packetUBXTIMTP->automaticFlags.flags.all = 0;
13214+ packetUBXTIMTP->callbackPointerPtr = nullptr;
13215+ packetUBXTIMTP->callbackData = nullptr;
13216+ packetUBXTIMTP->moduleQueried.moduleQueried.all = 0;
13217+ return (true);
13218+ }
13219+
13220+ // Mark all the data as read/stale
13221+ void DevUBLOXGNSS::flushTIMTP()
13222+ {
13223+ if (packetUBXTIMTP == nullptr)
13224+ return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
13225+ packetUBXTIMTP->moduleQueried.moduleQueried.all = 0; // Mark all datums as stale (read before)
13226+ }
13227+
13228+ // Log this data in file buffer
13229+ void DevUBLOXGNSS::logTIMTP(bool enabled)
13230+ {
13231+ if (packetUBXTIMTP == nullptr)
13232+ return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
13233+ packetUBXTIMTP->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
13234+ }
13235+
1301313236#ifndef SFE_UBLOX_DISABLE_ESF
1301413237// ***** ESF ALG automatic support
1301513238
@@ -16545,6 +16768,84 @@ uint8_t DevUBLOXGNSS::getAOPSTATUSstatus(uint16_t maxWait)
1654516768 return (packetUBXNAVAOPSTATUS->data.status);
1654616769}
1654716770
16771+ // ***** TIM TP Helper Functions
16772+
16773+ uint32_t DevUBLOXGNSS::getTIMTPtowMS(uint16_t maxWait)
16774+ {
16775+ if (packetUBXTIMTP == nullptr)
16776+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the TP data
16777+ if (packetUBXTIMTP == nullptr) // Bail if the RAM allocation failed
16778+ return 0;
16779+
16780+ if (packetUBXTIMTP->moduleQueried.moduleQueried.bits.towMS == false)
16781+ getTIMTP(maxWait);
16782+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.towMS = false; // Since we are about to give this to user, mark this data as stale
16783+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.all = false;
16784+ return (packetUBXTIMTP->data.towMS);
16785+ }
16786+
16787+ uint32_t DevUBLOXGNSS::getTIMTPtowSubMS(uint16_t maxWait)
16788+ {
16789+ if (packetUBXTIMTP == nullptr)
16790+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the TP data
16791+ if (packetUBXTIMTP == nullptr) // Bail if the RAM allocation failed
16792+ return 0;
16793+
16794+ if (packetUBXTIMTP->moduleQueried.moduleQueried.bits.towSubMS == false)
16795+ getTIMTP(maxWait);
16796+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.towSubMS = false; // Since we are about to give this to user, mark this data as stale
16797+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.all = false;
16798+ return (packetUBXTIMTP->data.towSubMS);
16799+ }
16800+
16801+ uint16_t DevUBLOXGNSS::getTIMTPweek(uint16_t maxWait)
16802+ {
16803+ if (packetUBXTIMTP == nullptr)
16804+ initPacketUBXTIMTP(); // Check that RAM has been allocated for the TP data
16805+ if (packetUBXTIMTP == nullptr) // Bail if the RAM allocation failed
16806+ return 0;
16807+
16808+ if (packetUBXTIMTP->moduleQueried.moduleQueried.bits.week == false)
16809+ getTIMTP(maxWait);
16810+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.week = false; // Since we are about to give this to user, mark this data as stale
16811+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.all = false;
16812+ return (packetUBXTIMTP->data.week);
16813+ }
16814+
16815+ // Convert TIM TP to Unix epoch including microseconds
16816+ // CAUTION! Assumes the time base is UTC and the week number is GPS
16817+ uint32_t DevUBLOXGNSS::getTIMTPAsEpoch(uint32_t µsecond, uint16_t maxWait)
16818+ {
16819+ if (packetUBXNAVPVT == nullptr)
16820+ initPacketUBXNAVPVT(); // Check that RAM has been allocated for the PVT data
16821+ if (packetUBXNAVPVT == nullptr) // Bail if the RAM allocation failed
16822+ return 0;
16823+
16824+ if (packetUBXTIMTP->moduleQueried.moduleQueried.bits.week == false)
16825+ getTIMTP(maxWait);
16826+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.week = false; // Since we are about to give this to user, mark this data as stale
16827+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.towMS = false;
16828+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.towSubMS = false;
16829+ packetUBXTIMTP->moduleQueried.moduleQueried.bits.all = false;
16830+
16831+ uint32_t tow = packetUBXTIMTP->data.week - SFE_UBLOX_JAN_1ST_2020_WEEK; // Calculate the number of weeks since Jan 1st 2020
16832+ tow *= SFE_UBLOX_SECS_PER_WEEK; // Convert weeks to seconds
16833+ tow += SFE_UBLOX_EPOCH_WEEK_2086; // Add the TOW for Jan 1st 2020
16834+ tow += packetUBXTIMTP->data.towMS / 1000; // Add the TOW for the next TP
16835+
16836+ uint32_t us = packetUBXTIMTP->data.towMS % 1000; // Extract the milliseconds
16837+ us *= 1000; // Convert to microseconds
16838+
16839+ double subMS = packetUBXTIMTP->data.towSubMS; // Get towSubMS (ms * 2^-32)
16840+ subMS *= pow(2.0, -32.0); // Convert to milliseconds
16841+ subMS *= 1000; // Convert to microseconds
16842+
16843+ us += (int32_t)subMS; // Add subMS
16844+
16845+ microsecond = us;
16846+ return tow;
16847+ }
16848+
1654816849#ifndef SFE_UBLOX_DISABLE_ESF
1654916850// ***** ESF Helper Functions
1655016851
0 commit comments