Skip to content

Commit 1206964

Browse files
committed
Expose ftime (SX1302/SX1303) as plain fine-timestamp if available.
Closes #193.
1 parent 2930b50 commit 1206964

File tree

2 files changed

+113
-18
lines changed

2 files changed

+113
-18
lines changed

internal/backend/semtechudp/packets/push_data.go

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/brocaar/chirpstack-api/go/v3/common"
1515
"github.com/brocaar/chirpstack-api/go/v3/gw"
1616
"github.com/brocaar/lorawan"
17+
"github.com/brocaar/lorawan/gps"
1718
)
1819

1920
// loRaDataRateRegex contains a regexp for parsing the LoRa data-rate string.
@@ -202,6 +203,29 @@ func getUplinkFrame(gatewayID []byte, rxpk RXPK, FakeRxInfoTime bool) (gw.Uplink
202203
frame.RxInfo.TimeSinceGpsEpoch = ptypes.DurationProto(d)
203204
}
204205

206+
// Plain fine-timestamp (SX1302 / SX1303)
207+
if rxpk.Tmms != nil && rxpk.FTime != nil {
208+
d := time.Duration(*rxpk.Tmms) * time.Millisecond
209+
210+
// take the seconds from the gps time
211+
d = d - (d % time.Second)
212+
// add the nanos from the fine-timestamp
213+
d = d + (time.Duration(*rxpk.FTime) * time.Nanosecond)
214+
215+
t := time.Time(gps.NewTimeFromTimeSinceGPSEpoch(d))
216+
tProto, err := ptypes.TimestampProto(t)
217+
if err != nil {
218+
return frame, errors.Wrap(err, "backend/semtechudp/packets: could not convert timestamp to proto timestamp")
219+
}
220+
221+
frame.RxInfo.FineTimestampType = gw.FineTimestampType_PLAIN
222+
frame.RxInfo.FineTimestamp = &gw.UplinkRXInfo_PlainFineTimestamp{
223+
PlainFineTimestamp: &gw.PlainFineTimestamp{
224+
Time: tProto,
225+
},
226+
}
227+
}
228+
205229
// LoRa data-rate
206230
if rxpk.DatR.LoRa != "" {
207231
frame.TxInfo.Modulation = common.Modulation_LORA
@@ -315,24 +339,25 @@ type Stat struct {
315339

316340
// RXPK contain a RF packet and associated metadata.
317341
type RXPK struct {
318-
Time *CompactTime `json:"time"` // UTC time of pkt RX, us precision, ISO 8601 'compact' format (e.g. 2013-03-31T16:21:17.528002Z)
319-
Tmms *int64 `json:"tmms"` // GPS time of pkt RX, number of milliseconds since 06.Jan.1980
320-
Tmst uint32 `json:"tmst"` // Internal timestamp of "RX finished" event (32b unsigned)
321-
AESK uint8 `json:"aesk"` //AES key index used for encrypting fine timestamps
322-
Chan uint8 `json:"chan"` // Concentrator "IF" channel used for RX (unsigned integer)
323-
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for RX (unsigned integer)
324-
Stat int8 `json:"stat"` // CRC status: 1 = OK, -1 = fail, 0 = no CRC
325-
Freq float64 `json:"freq"` // RX central frequency in MHz (unsigned float, Hz precision)
326-
Brd uint32 `json:"brd"` // Concentrator board used for RX (unsigned integer)
327-
RSSI int16 `json:"rssi"` // RSSI in dBm (signed integer, 1 dB precision)
328-
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
329-
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
330-
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
331-
CodR string `json:"codr"` // LoRa ECC coding rate identifier
332-
LSNR float64 `json:"lsnr"` // Lora SNR ratio in dB (signed float, 0.1 dB precision)
333-
HPW uint8 `json:"hpw"` // LR-FHSS hopping grid number of steps.
334-
Data []byte `json:"data"` // Base64 encoded RF packet payload, padded
335-
RSig []RSig `json:"rsig"` // Received signal information, per antenna (Optional)
342+
Time *CompactTime `json:"time"` // UTC time of pkt RX, us precision, ISO 8601 'compact' format (e.g. 2013-03-31T16:21:17.528002Z)
343+
Tmms *int64 `json:"tmms"` // GPS time of pkt RX, number of milliseconds since 06.Jan.1980
344+
Tmst uint32 `json:"tmst"` // Internal timestamp of "RX finished" event (32b unsigned)
345+
FTime *uint32 `json:"ftime"` // Fine timestamp, number of nanoseconds since last PPS [0..999999999] (Optional)
346+
AESK uint8 `json:"aesk"` // AES key index used for encrypting fine timestamps
347+
Chan uint8 `json:"chan"` // Concentrator "IF" channel used for RX (unsigned integer)
348+
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for RX (unsigned integer)
349+
Stat int8 `json:"stat"` // CRC status: 1 = OK, -1 = fail, 0 = no CRC
350+
Freq float64 `json:"freq"` // RX central frequency in MHz (unsigned float, Hz precision)
351+
Brd uint32 `json:"brd"` // Concentrator board used for RX (unsigned integer)
352+
RSSI int16 `json:"rssi"` // RSSI in dBm (signed integer, 1 dB precision)
353+
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
354+
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
355+
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
356+
CodR string `json:"codr"` // LoRa ECC coding rate identifier
357+
LSNR float64 `json:"lsnr"` // Lora SNR ratio in dB (signed float, 0.1 dB precision)
358+
HPW uint8 `json:"hpw"` // LR-FHSS hopping grid number of steps.
359+
Data []byte `json:"data"` // Base64 encoded RF packet payload, padded
360+
RSig []RSig `json:"rsig"` // Received signal information, per antenna (Optional)
336361
}
337362

338363
// RSig contains the received signal information per antenna.

internal/backend/semtechudp/packets/push_data_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/brocaar/chirpstack-api/go/v3/common"
1212
"github.com/brocaar/chirpstack-api/go/v3/gw"
1313
"github.com/brocaar/lorawan"
14+
"github.com/brocaar/lorawan/gps"
1415
)
1516

1617
func TestPushDataTest(t *testing.T) {
@@ -151,6 +152,10 @@ func TestGetUplinkFrame(t *testing.T) {
151152
assert.Nil(err)
152153

153154
tmms := int64(10 * time.Minute / time.Millisecond)
155+
ftime := uint32(999999999)
156+
157+
ft := time.Time(gps.NewTimeFromTimeSinceGPSEpoch((time.Duration(tmms) * time.Millisecond) + (time.Duration(ftime) * time.Nanosecond)))
158+
ftProto, _ := ptypes.TimestampProto(ft)
154159

155160
testTable := []struct {
156161
Name string
@@ -466,6 +471,71 @@ func TestGetUplinkFrame(t *testing.T) {
466471
},
467472
},
468473
},
474+
{
475+
Name: "With plain fine-timestamp (ftime)",
476+
PushDataPacket: PushDataPacket{
477+
GatewayMAC: lorawan.EUI64{1, 2, 3, 4, 5, 6, 7, 8},
478+
ProtocolVersion: ProtocolVersion2,
479+
Payload: PushDataPayload{
480+
RXPK: []RXPK{
481+
{
482+
Time: &ctNow,
483+
Tmms: &tmms,
484+
FTime: &ftime,
485+
Tmst: 1000000,
486+
Freq: 868.3,
487+
Brd: 2,
488+
Chan: 1,
489+
RFCh: 3,
490+
Stat: 1,
491+
Modu: "LORA",
492+
DatR: DatR{LoRa: "SF12BW500"},
493+
CodR: "4/5",
494+
RSSI: -60,
495+
LSNR: 5.5,
496+
Size: 5,
497+
Data: []byte{1, 2, 3, 4, 5},
498+
},
499+
},
500+
},
501+
},
502+
UplinkFrames: []gw.UplinkFrame{
503+
{
504+
PhyPayload: []byte{1, 2, 3, 4, 5},
505+
TxInfo: &gw.UplinkTXInfo{
506+
Frequency: 868300000,
507+
Modulation: common.Modulation_LORA,
508+
ModulationInfo: &gw.UplinkTXInfo_LoraModulationInfo{
509+
LoraModulationInfo: &gw.LoRaModulationInfo{
510+
Bandwidth: 500,
511+
SpreadingFactor: 12,
512+
CodeRate: "4/5",
513+
PolarizationInversion: false,
514+
},
515+
},
516+
},
517+
RxInfo: &gw.UplinkRXInfo{
518+
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
519+
Time: pbTime,
520+
TimeSinceGpsEpoch: ptypes.DurationProto(10 * time.Minute),
521+
Rssi: -60,
522+
LoraSnr: 5.5,
523+
Channel: 1,
524+
RfChain: 3,
525+
Board: 2,
526+
Antenna: 0,
527+
Context: []byte{0x00, 0x0f, 0x42, 0x40},
528+
CrcStatus: gw.CRCStatus_CRC_OK,
529+
FineTimestampType: gw.FineTimestampType_PLAIN,
530+
FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{
531+
PlainFineTimestamp: &gw.PlainFineTimestamp{
532+
Time: ftProto,
533+
},
534+
},
535+
},
536+
},
537+
},
538+
},
469539
}
470540

471541
for _, test := range testTable {

0 commit comments

Comments
 (0)