@@ -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