packet_forwarder
packet_forwarder copied to clipboard
Time information not sent when faking GPS module
When the gateway is not equipped with a GPS module and is configured with fake_gps: true
, the time information is not added to the "DeviceTimeAns" MAC command specified in LoRaWAN 1.0.3.
Browsing the code I found a couple of TODOs that mention the possibility of using an alternative time source from the GPS module:
A solution could use the clock_gettime()
function with CLOCK_REALTIME
to get the seconds since the Unix epoch, and then convert to seconds since the GPS epoch (taking into consideration leap seconds..).
I see two way of enabling the behaviour of using the local time:
- by adding a new option, e.g. "fake_gps_time", or
- by enabling reading the local time whenever
gps_ref_valid
isfalse
.
I'm willing to propose a PR, but I'm not an expert in C or the codebase, so I might need a little guidance.
MAC commands are processed by the back-end, not the gateway (also not the packet forwarder on the gateway) so I assume your statement is based on back-end code? What code?
Maybe you're right, and the problem lies in the Network Server software. As I mentioned before, I'm not an expert, and I'm still trying to figure stuff out.
I thought it was due to packet_forwarder because of the TODO
s I found skimming the code and the # Invalid gps time reference
messages I was seeing in the logs.
I'll investigate more thoroughly and report back.
I'll report here the results of my research.
Loraserver
First, I tried to understand why the Loraserver was sending a zero payload for the DeviceTimeAns
.
Basically, when the loraserver
software receives a request of the DeviceTimeReq
MAC command, it will answer copying the timestamp of the received packet.
You can see this behaviour in the handleDeviceTimeReq()
function:
-
here the function reads the
TimeSinceGpsEpoch
field of therxInfo
structure into thetimeSinceGPSEpoch
variable, as follows:timeSinceGPSEpoch, err = ptypes.Duration(rxInfo.TimeSinceGpsEpoch)
-
here the
timeSinceGPSEpoch
variable is used to populate the payload of theDeviceTimeAns
MAC command.MACCommands: storage.MACCommands{ { CID: lorawan.DeviceTimeAns, Payload: &lorawan.DeviceTimeAnsPayload{ TimeSinceGPSEpoch: timeSinceGPSEpoch, }, }, },
So if the DeviceTimeAns
payload is zero, it's because the rxInfo.TimeSinceGpsEpoch
field is zero.
This field is read from..
Lora-gateway-bridge
The next layer of the network is the Lora-gateway-bridge.
Turns out the TimeSinceGpsEpoch
field is populated using the "tmms" field of the JSON object received by the packet_forwarder
, as seen here
// Time since GPS epoch
if rxpk.Tmms != nil {
d := time.Duration(*rxpk.Tmms) * time.Millisecond
frame.RxInfo.TimeSinceGpsEpoch = ptypes.DurationProto(d)
}
So how is the "tmms" field set?
packet_forwarder
The lora-gateway-bridge reads the JSON sent by packet_forwarder. It turns out the "tmms" field is always missing from this JSON.
I could only find it mentioned in the PROTOCOL.TXT
of the packet_forwarder from Lora-Net
Conclusions
Probably the easiest solution is patching the lora-gateway-bridge so that it uses the "time" field rather then "tmms" to set RxInfo.TimeSinceGpsEpoch
.
A little update. I forked the packet_forwader from Lora-net to add the "tmms" field in the uplink JSON.
With that modification, the DeviceTimeAns
and DeviceTimeReq
comands work correctly.