timeSinceGPSEpoch too big

Hi All!!!

I’m trying to use Class B, but DeviceTimeReq in the downlink is too big (timeSinceGPSEpoch:1238254065335937500) .
I use LoRa Gateway OS in the RPi3 & Rak831 & GPS.

Some advice/solution?

Thank!

It seems like the timestamp shown is a GPS time in nanoseconds. You are probably expecting it in seconds. To convert, simply use only the first ten digits.

Check with GPS Time Converter
In your example, it would be 1238254065.

I am wondering whether ChirpStack transmits the timestamp correctly though. I see in the LoRaWAN Link Layer Specification v1.0.4.pdf that there are supposed to be in the DeviceTimeAns payload
4 octets for seconds since epoch (which is what you expected)
1 octet for fractional-second in 256 increments

I suspect ChirpStack actually sends out nanoseconds as shown in the JSON payload, instead of the format described in the specification.

It is send as seconds when encoded to a LoRaWAN frame:

// DeviceTimeAnsPayload represents the DeviceTimeAns payload.
type DeviceTimeAnsPayload struct {
	TimeSinceGPSEpoch time.Duration `json:"timeSinceGPSEpoch"`
}

// MarshalBinary encodes the object into bytes.
func (p DeviceTimeAnsPayload) MarshalBinary() ([]byte, error) {
	b := make([]byte, 5)

	seconds := uint32(p.TimeSinceGPSEpoch / time.Second)
	binary.LittleEndian.PutUint32(b, seconds)

	// time.Second / 256 = 3906250ns
	b[4] = uint8((p.TimeSinceGPSEpoch - (time.Duration(seconds) * time.Second)) / 3906250)

	return b, nil
}

2 Likes

Ah, thank you. This clarifies the first four bytes for me.

It might be my ignorance about Go, but where is the 5th byte assigned (1/256 seconds)?

/edit: I am just dense, it’s right there:

	// time.Second / 256 = 3906250ns
b[4] = uint8((p.TimeSinceGPSEpoch - (time.Duration(seconds) * time.Second)) / 3906250)

For anyone else, the code is here: