Skip to content

Commit

Permalink
Correct tmms implementation (time since gps epoch).
Browse files Browse the repository at this point in the history
  • Loading branch information
brocaar committed Dec 12, 2017
1 parent 555c46f commit 556f311
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 92 deletions.
11 changes: 8 additions & 3 deletions docs/content/overview/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ menu:
* LoRa Gateway Bridge now publishes TX acknowledgement messages over MQTT.
See [MQTT topics](https://docs.loraserver.io/lora-gateway-bridge/use/data/).

* TX (GPS) time field is now implemented to transmit at given timestamp
(only possible when the gateway has a GPS time-source).
* TX (GPS) `timeSinceGPSEpoch` field is now exposed to transmit at given
time since GPS epoch (1980-01-06, only possible when the gateway
has a GPS time source).

* RX (GPS) `timeSinceGPSEpoch` field is now exposed, containing the time
since GPS epoch (1980-01-06, only available when the gateway has a GPS
time source).

**Bugfixes:**

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


Expand Down
9 changes: 5 additions & 4 deletions docs/content/use/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ Topic for received packets (from nodes). Example payload:
"rfChain": 1,
"rssi": -57,
"size": 23,
"time": "2017-12-11T10:14:54.619571Z", // timestamp (only set when the gateway has a GPS time-source)
"time": "2017-12-12T15:28:53.222434Z", // timestamp (only set when the gateway has a GPS time source)
"timeSinceGPSEpoch": "332535h29m12.222s", // time since GPS epoch (only set when the gateway has a GPS time source)
"timestamp": 2074240683 // gateway internal timestamp (32 bit) with microsecond precision
}
}
Expand Down Expand Up @@ -92,14 +93,14 @@ Example payload:
"immediately": false,
"mac": "1dee08d0b691d149",
"power": 14,
"timestamp": 2079240683, // gateway internal timestamp for transmission -OR-
"time": "2017-12-11T10:14:54.619571Z" // timestamp for transmission (only when the gateway has a GPS time-source)
"timestamp": 2079240683, // gateway internal timestamp for transmission -OR-
"timeSinceGPSEpoch": "332535h29m12.222s" // time since GPS epoch (only when the gateway has a GPS time source)
}
}
```

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

Optionally, the field `iPol` (type `bool`) can be used to control the
Expand Down
11 changes: 8 additions & 3 deletions gateway/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,11 @@ func newRXPacketsFromRXPK(mac lorawan.EUI64, rxpk RXPK) ([]gw.RXPacketBytes, err
rxPacket.RXInfo.Time = &ts
}

if rxpk.Tmms != nil {
d := gw.Duration(time.Duration(*rxpk.Tmms) * time.Millisecond)
rxPacket.RXInfo.TimeSinceGPSEpoch = &d
}

if len(rxpk.RSig) == 0 {
rxPackets = append(rxPackets, rxPacket)
}
Expand Down Expand Up @@ -481,9 +486,9 @@ func newTXPKFromTXPacket(txPacket gw.TXPacketBytes) (TXPK, error) {
Brd: uint8(txPacket.TXInfo.Board),
}

if txPacket.TXInfo.Time != nil {
ct := CompactTime(*txPacket.TXInfo.Time)
txpk.Tmms = &ct
if txPacket.TXInfo.TimeSinceGPSEpoch != nil {
tmms := int64(time.Duration(*txPacket.TXInfo.TimeSinceGPSEpoch) / time.Millisecond)
txpk.Tmms = &tmms
}

if txPacket.TXInfo.DataRate.Modulation == band.FSKModulation {
Expand Down
85 changes: 47 additions & 38 deletions gateway/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func TestBackend(t *testing.T) {

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

p := PushDataPacket{
ProtocolVersion: ProtocolVersion2,
Expand All @@ -171,6 +172,7 @@ func TestBackend(t *testing.T) {
{
Time: &ts,
Tmst: 708016819,
Tmms: &tmms,
Freq: 868.5,
Chan: 2,
RFCh: 1,
Expand Down Expand Up @@ -359,17 +361,16 @@ func TestBackend(t *testing.T) {

Convey("Given a TXPacket", func() {
internalTS := uint32(12345)
ts := time.Now().UTC()
tsCompact := CompactTime(ts)
timeSinceGPSEpoch := gw.Duration(time.Second)

txPacket := gw.TXPacketBytes{
TXInfo: gw.TXInfo{
MAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
Immediately: true,
Timestamp: &internalTS,
Time: &ts,
Frequency: 868100000,
Power: 14,
MAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
Immediately: true,
Timestamp: &internalTS,
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
Frequency: 868100000,
Power: 14,
DataRate: band.DataRate{
Modulation: band.LoRaModulation,
SpreadFactor: 12,
Expand Down Expand Up @@ -419,13 +420,14 @@ func TestBackend(t *testing.T) {
var pullResp PullRespPacket
So(pullResp.UnmarshalBinary(buf[:i]), ShouldBeNil)

tmms := int64(time.Second / time.Millisecond)
So(pullResp, ShouldResemble, PullRespPacket{
ProtocolVersion: p.ProtocolVersion,
Payload: PullRespPayload{
TXPK: TXPK{
Imme: true,
Tmst: &internalTS,
Tmms: &tsCompact,
Tmms: &tmms,
Freq: 868.1,
Powe: 14,
Modu: "LORA",
Expand Down Expand Up @@ -520,17 +522,17 @@ func TestNewGatewayStatPacket(t *testing.T) {

func TestNewTXPKFromTXPacket(t *testing.T) {
internalTS := uint32(12345)
ts := time.Now().UTC()
tsCompact := CompactTime(ts)

Convey("Given a TXPacket", t, func() {
timeSinceGPSEpoch := gw.Duration(time.Second)

txPacket := gw.TXPacketBytes{
TXInfo: gw.TXInfo{
Timestamp: &internalTS,
Time: &ts,
Frequency: 868100000,
Power: 14,
CodeRate: "4/5",
Timestamp: &internalTS,
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
Frequency: 868100000,
Power: 14,
CodeRate: "4/5",
DataRate: band.DataRate{
Modulation: band.LoRaModulation,
SpreadFactor: 9,
Expand All @@ -543,12 +545,13 @@ func TestNewTXPKFromTXPacket(t *testing.T) {
}

Convey("Then te expected TXPK is returned (with default IPol", func() {
tmms := int64(time.Second / time.Millisecond)
txpk, err := newTXPKFromTXPacket(txPacket)
So(err, ShouldBeNil)
So(txpk, ShouldResemble, TXPK{
Imme: false,
Tmst: &internalTS,
Tmms: &tsCompact,
Tmms: &tmms,
Freq: 868.1,
Powe: 14,
Modu: "LORA",
Expand Down Expand Up @@ -581,9 +584,12 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
Convey("Given a RXPK and gateway MAC", t, func() {
now := time.Now().UTC()
nowCompact := CompactTime(now)
tmms := int64(time.Second / time.Millisecond)
timeSinceGPSEpoch := gw.Duration(time.Second)

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

So(rxPackets[0].RXInfo, ShouldResemble, gw.RXInfo{
MAC: mac,
Time: &now,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 2,
RFChain: 1,
CRCStatus: 1,
MAC: mac,
Time: &now,
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 2,
RFChain: 1,
CRCStatus: 1,
DataRate: band.DataRate{
Modulation: band.LoRaModulation,
SpreadFactor: 7,
Expand Down Expand Up @@ -651,13 +658,14 @@ func TestNewRXPacketFromRXPK(t *testing.T) {
Convey("Then all fields are set correctly", func() {
So(rxPackets[0].PHYPayload, ShouldResemble, []byte{1, 2, 3, 4})
So(rxPackets[0].RXInfo, ShouldResemble, gw.RXInfo{
MAC: mac,
Time: &now,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 3,
RFChain: 1,
CRCStatus: 1,
MAC: mac,
Time: &now,
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 3,
RFChain: 1,
CRCStatus: 1,
DataRate: band.DataRate{
Modulation: band.LoRaModulation,
SpreadFactor: 7,
Expand All @@ -673,13 +681,14 @@ func TestNewRXPacketFromRXPK(t *testing.T) {

So(rxPackets[1].PHYPayload, ShouldResemble, []byte{1, 2, 3, 4})
So(rxPackets[1].RXInfo, ShouldResemble, gw.RXInfo{
MAC: mac,
Time: &now,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 3,
RFChain: 1,
CRCStatus: 1,
MAC: mac,
Time: &now,
TimeSinceGPSEpoch: &timeSinceGPSEpoch,
Timestamp: 708016819,
Frequency: 868500000,
Channel: 3,
RFChain: 1,
CRCStatus: 1,
DataRate: band.DataRate{
Modulation: band.LoRaModulation,
SpreadFactor: 7,
Expand Down
35 changes: 18 additions & 17 deletions gateway/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ func (d *DatR) UnmarshalJSON(data []byte) error {
// RXPK contain a RF packet and associated metadata.
type RXPK struct {
Time *CompactTime `json:"time"` // UTC time of pkt RX, us precision, ISO 8601 'compact' format (e.g. 2013-03-31T16:21:17.528002Z)
Tmms *int64 `json:"tmms"` // GPS time of pkt RX, number of milliseconds since 06.Jan.1980
Tmst uint32 `json:"tmst"` // Internal timestamp of "RX finished" event (32b unsigned)
Freq float64 `json:"freq"` // RX central frequency in MHz (unsigned float, Hz precision)
Brd uint8 `json:"brd"` // Concentrator board used for RX (unsigned integer)
Expand Down Expand Up @@ -417,23 +418,23 @@ type Stat struct {

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

// GetPacketType returns the packet type for the given packet data.
Expand Down
76 changes: 51 additions & 25 deletions vendor/github.com/brocaar/loraserver/api/gw/gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 556f311

Please sign in to comment.