GN: Unix Timestamp Synchronization

I’d like to update the timestamp on the Generic Node (GN). The goal is for the gateway to send a Unix timestamp to the GN, which would then store it in non-volatile memory.

However, updating the GN’s local time isn’t straightforward. The system time (SysTime_t) is represented as a struct with two fields: Seconds and SubSeconds. While I could use the SysTimeSet() function from the Utilities module, it doesn’t seem to be designed specifically for setting a Unix timestamp.

Is there a built-in function in the lower layers of LoRaWAN that handles Unix timestamps directly? I’m aware that ADR is implemented, but not sure about time synchronization.

About 85.72% yes and about 17.34% no, or thereabouts.

There is a MAC request in LW for requesting the time. Then you have to massage it for the difference between GPS and UTC time (from memory) and then set the RTC.

The LW Special Forces Team will drop you down a deep dark hole if you uplink on a precise schedule - see TR007 (yes, it’s that serious that Jame Bond will be despatched to get you).

Hi

Thanks for the help! I’ve gone through the documentation and the code, and I have quite a few questions. Are any of the original developers active on this forum?

I have found the functionality I need in the lower layers of GN. Essentially, it is the MAC command DeviceTimeAns that would do the thing I want. It receives the GPS timestamp from the gateway, converts it to a Unix timestamp and stores it as the GN’s system time. This means that I only need to send a DeviceTimeReq, where I would get a response and the DeviceTimeAns command would be executed.

However, I am not sure how to send the command. Initially, I thought I had to call LmHandlerDeviceTimeReq() to send a request. However, the function is declared static, meaning it is private. There is a reason for that, right?

In LoRaWAN 1.0.0, the AppTimeReq command is used to update the node’s timestamp. In the new version (1.1.0), however, DeviceTimeReq is used instead. Having read an old document on the LoRaWAN 1.0.0 Application Layer Clock Synchronisation Specification, I discovered that you need to deactivate ADR and set NbTrans = 1 before sending the AppTimeReq command. As these commands do the same thing, perhaps you also need to do the same for DeviceTimeReq.

After digging deeper into the code, I saw that you do indeed need to deactivate the ADR, set the NbTrans = 1 and also store the datarate. However, rather than calling the function, you initialise a structure of functional pointers and add it to your LoRaMAC handlers, where it is called by the LoRaWAN lower layers. In order to add the handlers, do I need to call LmHandlerPackageRegister with PACKAGE_ID_CLOCK_SYNC? Does this mean the handlers are called whenever there is a TX or RX process?

If so, this seems a bit too aggressive. I would only like this to happen when joining and once per day at most.

I noticed that the GN was implemented according to the LoRaWAN 1.0.2 specification. Does this mean that the DeviceTimeReq command is not yet finished?

If any of my assumptions are incorrect, please feel free to correct me.

Thanks for the help!

Yes, no, maybe. Original developers of what? The hardware? Irrelevant but he does occasionally pop by. The firmware? Haven’t seen him in years, but irrelevant because the hardware guy knows the firmware. So I guess you need someone that knows LoRaMac-node and has a GNSE and codes for the STM32WL …

Paging @CaptainAwesome.

In the meanwhile, I can assure you that most of your assumptions are incorrect and it isn’t meant to be this hard. Let’s await on Awesomeness …

Hi

I think I have found the correct way to do it, but I’m not entirely sure. The timestamp is updated, but not always successfully. Sometimes I have to do it again and then it works. Is there a specific procedure for setting it? I am doing the Device Time request after the join request.

This is how I send a device time request to the gateway or concentrator:

    // send the DeviceTimeReq
    MlmeReq_t mlmeReq;
    mlmeReq.Type = MLME_DEVICE_TIME;
    LoRaMacStatus_t ret = LoRaMacMlmeRequest(&mlmeReq);
    if (start_transmission_now && (ret == LORAMAC_STATUS_OK))
    {
      // this needs to be done as the command is executed when a transmission is running (piggyback )
      LmHandlerAppData_t appData =
      {
        .Buffer = NULL,
        .BufferSize = 0,
        .Port = SENSORS_PAYLOAD_APP_PORT
      };
      LmHandlerSend(&appData, LORAMAC_HANDLER_UNCONFIRMED_MSG, NULL, false);
      APP_LOG(ADV_TRACER_TS_OFF, ADV_TRACER_VLEVEL_M, "DeviceTimeReq: TX message has been sent. \r\n")
    }