Skip to content

Commit 556f311

Browse files
committed
Correct tmms implementation (time since gps epoch).
1 parent 555c46f commit 556f311

File tree

7 files changed

+139
-92
lines changed

7 files changed

+139
-92
lines changed

docs/content/overview/changelog.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ menu:
1515
* LoRa Gateway Bridge now publishes TX acknowledgement messages over MQTT.
1616
See [MQTT topics](https://docs.loraserver.io/lora-gateway-bridge/use/data/).
1717

18-
* TX (GPS) time field is now implemented to transmit at given timestamp
19-
(only possible when the gateway has a GPS time-source).
18+
* TX (GPS) `timeSinceGPSEpoch` field is now exposed to transmit at given
19+
time since GPS epoch (1980-01-06, only possible when the gateway
20+
has a GPS time source).
21+
22+
* RX (GPS) `timeSinceGPSEpoch` field is now exposed, containing the time
23+
since GPS epoch (1980-01-06, only available when the gateway has a GPS
24+
time source).
2025

2126
**Bugfixes:**
2227

23-
* Without GPS time-source, the gateway would use `0001-01-01T00:00:00Z`
28+
* Without GPS time source, the gateway would use `0001-01-01T00:00:00Z`
2429
as RX `time`. The `time` field is now omitted when unavailable.
2530

2631

docs/content/use/data.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ Topic for received packets (from nodes). Example payload:
6464
"rfChain": 1,
6565
"rssi": -57,
6666
"size": 23,
67-
"time": "2017-12-11T10:14:54.619571Z", // timestamp (only set when the gateway has a GPS time-source)
67+
"time": "2017-12-12T15:28:53.222434Z", // timestamp (only set when the gateway has a GPS time source)
68+
"timeSinceGPSEpoch": "332535h29m12.222s", // time since GPS epoch (only set when the gateway has a GPS time source)
6869
"timestamp": 2074240683 // gateway internal timestamp (32 bit) with microsecond precision
6970
}
7071
}
@@ -92,14 +93,14 @@ Example payload:
9293
"immediately": false,
9394
"mac": "1dee08d0b691d149",
9495
"power": 14,
95-
"timestamp": 2079240683, // gateway internal timestamp for transmission -OR-
96-
"time": "2017-12-11T10:14:54.619571Z" // timestamp for transmission (only when the gateway has a GPS time-source)
96+
"timestamp": 2079240683, // gateway internal timestamp for transmission -OR-
97+
"timeSinceGPSEpoch": "332535h29m12.222s" // time since GPS epoch (only when the gateway has a GPS time source)
9798
}
9899
}
99100
```
100101

101102
When `immediately` is set to `false`, either the `timestamp` **or** the
102-
`time` field must be present to tell the gateway at what (internal) time
103+
`timeSinceGPSEpoch` field must be present to tell the gateway at what (internal) time
103104
the frame must be transmitted.
104105

105106
Optionally, the field `iPol` (type `bool`) can be used to control the

gateway/backend.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,11 @@ func newRXPacketsFromRXPK(mac lorawan.EUI64, rxpk RXPK) ([]gw.RXPacketBytes, err
448448
rxPacket.RXInfo.Time = &ts
449449
}
450450

451+
if rxpk.Tmms != nil {
452+
d := gw.Duration(time.Duration(*rxpk.Tmms) * time.Millisecond)
453+
rxPacket.RXInfo.TimeSinceGPSEpoch = &d
454+
}
455+
451456
if len(rxpk.RSig) == 0 {
452457
rxPackets = append(rxPackets, rxPacket)
453458
}
@@ -481,9 +486,9 @@ func newTXPKFromTXPacket(txPacket gw.TXPacketBytes) (TXPK, error) {
481486
Brd: uint8(txPacket.TXInfo.Board),
482487
}
483488

484-
if txPacket.TXInfo.Time != nil {
485-
ct := CompactTime(*txPacket.TXInfo.Time)
486-
txpk.Tmms = &ct
489+
if txPacket.TXInfo.TimeSinceGPSEpoch != nil {
490+
tmms := int64(time.Duration(*txPacket.TXInfo.TimeSinceGPSEpoch) / time.Millisecond)
491+
txpk.Tmms = &tmms
487492
}
488493

489494
if txPacket.TXInfo.DataRate.Modulation == band.FSKModulation {

gateway/backend_test.go

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ func TestBackend(t *testing.T) {
161161

162162
Convey("When sending a PUSH_DATA packet with RXPK (CRC OK + GPS timestamp)", func() {
163163
ts := CompactTime(time.Now().UTC())
164+
tmms := int64(time.Second / time.Millisecond)
164165

165166
p := PushDataPacket{
166167
ProtocolVersion: ProtocolVersion2,
@@ -171,6 +172,7 @@ func TestBackend(t *testing.T) {
171172
{
172173
Time: &ts,
173174
Tmst: 708016819,
175+
Tmms: &tmms,
174176
Freq: 868.5,
175177
Chan: 2,
176178
RFCh: 1,
@@ -359,17 +361,16 @@ func TestBackend(t *testing.T) {
359361

360362
Convey("Given a TXPacket", func() {
361363
internalTS := uint32(12345)
362-
ts := time.Now().UTC()
363-
tsCompact := CompactTime(ts)
364+
timeSinceGPSEpoch := gw.Duration(time.Second)
364365

365366
txPacket := gw.TXPacketBytes{
366367
TXInfo: gw.TXInfo{
367-
MAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
368-
Immediately: true,
369-
Timestamp: &internalTS,
370-
Time: &ts,
371-
Frequency: 868100000,
372-
Power: 14,
368+
MAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
369+
Immediately: true,
370+
Timestamp: &internalTS,
371+
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
372+
Frequency: 868100000,
373+
Power: 14,
373374
DataRate: band.DataRate{
374375
Modulation: band.LoRaModulation,
375376
SpreadFactor: 12,
@@ -419,13 +420,14 @@ func TestBackend(t *testing.T) {
419420
var pullResp PullRespPacket
420421
So(pullResp.UnmarshalBinary(buf[:i]), ShouldBeNil)
421422

423+
tmms := int64(time.Second / time.Millisecond)
422424
So(pullResp, ShouldResemble, PullRespPacket{
423425
ProtocolVersion: p.ProtocolVersion,
424426
Payload: PullRespPayload{
425427
TXPK: TXPK{
426428
Imme: true,
427429
Tmst: &internalTS,
428-
Tmms: &tsCompact,
430+
Tmms: &tmms,
429431
Freq: 868.1,
430432
Powe: 14,
431433
Modu: "LORA",
@@ -520,17 +522,17 @@ func TestNewGatewayStatPacket(t *testing.T) {
520522

521523
func TestNewTXPKFromTXPacket(t *testing.T) {
522524
internalTS := uint32(12345)
523-
ts := time.Now().UTC()
524-
tsCompact := CompactTime(ts)
525525

526526
Convey("Given a TXPacket", t, func() {
527+
timeSinceGPSEpoch := gw.Duration(time.Second)
528+
527529
txPacket := gw.TXPacketBytes{
528530
TXInfo: gw.TXInfo{
529-
Timestamp: &internalTS,
530-
Time: &ts,
531-
Frequency: 868100000,
532-
Power: 14,
533-
CodeRate: "4/5",
531+
Timestamp: &internalTS,
532+
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
533+
Frequency: 868100000,
534+
Power: 14,
535+
CodeRate: "4/5",
534536
DataRate: band.DataRate{
535537
Modulation: band.LoRaModulation,
536538
SpreadFactor: 9,
@@ -543,12 +545,13 @@ func TestNewTXPKFromTXPacket(t *testing.T) {
543545
}
544546

545547
Convey("Then te expected TXPK is returned (with default IPol", func() {
548+
tmms := int64(time.Second / time.Millisecond)
546549
txpk, err := newTXPKFromTXPacket(txPacket)
547550
So(err, ShouldBeNil)
548551
So(txpk, ShouldResemble, TXPK{
549552
Imme: false,
550553
Tmst: &internalTS,
551-
Tmms: &tsCompact,
554+
Tmms: &tmms,
552555
Freq: 868.1,
553556
Powe: 14,
554557
Modu: "LORA",
@@ -581,9 +584,12 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
581584
Convey("Given a RXPK and gateway MAC", t, func() {
582585
now := time.Now().UTC()
583586
nowCompact := CompactTime(now)
587+
tmms := int64(time.Second / time.Millisecond)
588+
timeSinceGPSEpoch := gw.Duration(time.Second)
584589

585590
rxpk := RXPK{
586591
Time: &nowCompact,
592+
Tmms: &tmms,
587593
Tmst: 708016819,
588594
Freq: 868.5,
589595
Chan: 2,
@@ -608,13 +614,14 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
608614
So(rxPackets[0].PHYPayload, ShouldResemble, []byte{1, 2, 3, 4})
609615

610616
So(rxPackets[0].RXInfo, ShouldResemble, gw.RXInfo{
611-
MAC: mac,
612-
Time: &now,
613-
Timestamp: 708016819,
614-
Frequency: 868500000,
615-
Channel: 2,
616-
RFChain: 1,
617-
CRCStatus: 1,
617+
MAC: mac,
618+
Time: &now,
619+
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
620+
Timestamp: 708016819,
621+
Frequency: 868500000,
622+
Channel: 2,
623+
RFChain: 1,
624+
CRCStatus: 1,
618625
DataRate: band.DataRate{
619626
Modulation: band.LoRaModulation,
620627
SpreadFactor: 7,
@@ -651,13 +658,14 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
651658
Convey("Then all fields are set correctly", func() {
652659
So(rxPackets[0].PHYPayload, ShouldResemble, []byte{1, 2, 3, 4})
653660
So(rxPackets[0].RXInfo, ShouldResemble, gw.RXInfo{
654-
MAC: mac,
655-
Time: &now,
656-
Timestamp: 708016819,
657-
Frequency: 868500000,
658-
Channel: 3,
659-
RFChain: 1,
660-
CRCStatus: 1,
661+
MAC: mac,
662+
Time: &now,
663+
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
664+
Timestamp: 708016819,
665+
Frequency: 868500000,
666+
Channel: 3,
667+
RFChain: 1,
668+
CRCStatus: 1,
661669
DataRate: band.DataRate{
662670
Modulation: band.LoRaModulation,
663671
SpreadFactor: 7,
@@ -673,13 +681,14 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
673681

674682
So(rxPackets[1].PHYPayload, ShouldResemble, []byte{1, 2, 3, 4})
675683
So(rxPackets[1].RXInfo, ShouldResemble, gw.RXInfo{
676-
MAC: mac,
677-
Time: &now,
678-
Timestamp: 708016819,
679-
Frequency: 868500000,
680-
Channel: 3,
681-
RFChain: 1,
682-
CRCStatus: 1,
684+
MAC: mac,
685+
Time: &now,
686+
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
687+
Timestamp: 708016819,
688+
Frequency: 868500000,
689+
Channel: 3,
690+
RFChain: 1,
691+
CRCStatus: 1,
683692
DataRate: band.DataRate{
684693
Modulation: band.LoRaModulation,
685694
SpreadFactor: 7,

gateway/structs.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ func (d *DatR) UnmarshalJSON(data []byte) error {
377377
// RXPK contain a RF packet and associated metadata.
378378
type RXPK struct {
379379
Time *CompactTime `json:"time"` // UTC time of pkt RX, us precision, ISO 8601 'compact' format (e.g. 2013-03-31T16:21:17.528002Z)
380+
Tmms *int64 `json:"tmms"` // GPS time of pkt RX, number of milliseconds since 06.Jan.1980
380381
Tmst uint32 `json:"tmst"` // Internal timestamp of "RX finished" event (32b unsigned)
381382
Freq float64 `json:"freq"` // RX central frequency in MHz (unsigned float, Hz precision)
382383
Brd uint8 `json:"brd"` // Concentrator board used for RX (unsigned integer)
@@ -417,23 +418,23 @@ type Stat struct {
417418

418419
// TXPK contains a RF packet to be emitted and associated metadata.
419420
type TXPK struct {
420-
Imme bool `json:"imme"` // Send packet immediately (will ignore tmst & time)
421-
Tmst *uint32 `json:"tmst,omitempty"` // Send packet on a certain timestamp value (will ignore time)
422-
Tmms *CompactTime `json:"tmms,omitempty"` // Send packet at a certain time (GPS synchronization required)
423-
Freq float64 `json:"freq"` // TX central frequency in MHz (unsigned float, Hz precision)
424-
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for TX (unsigned integer)
425-
Powe uint8 `json:"powe"` // TX output power in dBm (unsigned integer, dBm precision)
426-
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
427-
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
428-
CodR string `json:"codr,omitempty"` // LoRa ECC coding rate identifier
429-
FDev uint16 `json:"fdev,omitempty"` // FSK frequency deviation (unsigned integer, in Hz)
430-
IPol bool `json:"ipol"` // Lora modulation polarization inversion
431-
Prea uint16 `json:"prea,omitempty"` // RF preamble size (unsigned integer)
432-
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
433-
NCRC bool `json:"ncrc,omitempty"` // If true, disable the CRC of the physical layer (optional)
434-
Data string `json:"data"` // Base64 encoded RF packet payload, padding optional
435-
Brd uint8 `json:"brd"` // Concentrator board used for RX (unsigned integer)
436-
Ant uint8 `json:"ant"` // Antenna number on which signal has been received
421+
Imme bool `json:"imme"` // Send packet immediately (will ignore tmst & time)
422+
Tmst *uint32 `json:"tmst,omitempty"` // Send packet on a certain timestamp value (will ignore time)
423+
Tmms *int64 `json:"tmms,omitempty"` // Send packet at a certain GPS time (GPS synchronization required)
424+
Freq float64 `json:"freq"` // TX central frequency in MHz (unsigned float, Hz precision)
425+
RFCh uint8 `json:"rfch"` // Concentrator "RF chain" used for TX (unsigned integer)
426+
Powe uint8 `json:"powe"` // TX output power in dBm (unsigned integer, dBm precision)
427+
Modu string `json:"modu"` // Modulation identifier "LORA" or "FSK"
428+
DatR DatR `json:"datr"` // LoRa datarate identifier (eg. SF12BW500) || FSK datarate (unsigned, in bits per second)
429+
CodR string `json:"codr,omitempty"` // LoRa ECC coding rate identifier
430+
FDev uint16 `json:"fdev,omitempty"` // FSK frequency deviation (unsigned integer, in Hz)
431+
IPol bool `json:"ipol"` // Lora modulation polarization inversion
432+
Prea uint16 `json:"prea,omitempty"` // RF preamble size (unsigned integer)
433+
Size uint16 `json:"size"` // RF packet payload size in bytes (unsigned integer)
434+
NCRC bool `json:"ncrc,omitempty"` // If true, disable the CRC of the physical layer (optional)
435+
Data string `json:"data"` // Base64 encoded RF packet payload, padding optional
436+
Brd uint8 `json:"brd"` // Concentrator board used for RX (unsigned integer)
437+
Ant uint8 `json:"ant"` // Antenna number on which signal has been received
437438
}
438439

439440
// GetPacketType returns the packet type for the given packet data.

vendor/github.com/brocaar/loraserver/api/gw/gw.go

Lines changed: 51 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)