Skip to content

Commit

Permalink
Update Semtech UDP backend to use new timing.
Browse files Browse the repository at this point in the history
  • Loading branch information
brocaar committed Apr 16, 2019
1 parent b9124a4 commit 08b8d7a
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 30 deletions.
36 changes: 18 additions & 18 deletions internal/backend/semtechudp/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ func (ts *BackendTestSuite) TestPushData() {
LoraSnr: 7,
Channel: 2,
RfChain: 1,
Context: []byte{0x2a, 0x33, 0x7a, 0xb3},
},
},
},
Expand Down Expand Up @@ -341,8 +342,7 @@ func (ts *BackendTestSuite) TestPushData() {
func (ts *BackendTestSuite) TestSendDownlinkFrame() {
assert := require.New(ts.T())

tmst := uint32(1234567)
tmms := int64(time.Second / time.Millisecond)
tmst := uint32(2000000)

testTable := []struct {
Name string
Expand All @@ -364,12 +364,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
Immediately: true,
TimeSinceGpsEpoch: &duration.Duration{
Seconds: 1,
},
Timestamp: tmst,
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_LORA,
Expand All @@ -381,8 +376,15 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
PolarizationInversion: true,
},
},
Timing: gw.DownlinkTiming_DELAY,
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
DelayTimingInfo: &gw.DelayTimingInfo{
Delay: ptypes.DurationProto(time.Second),
},
},
Board: 1,
Antenna: 2,
Context: []byte{0x00, 0x0f, 0x42, 0x40},
},
Token: 123,
},
Expand All @@ -391,9 +393,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
RandomToken: 123,
Payload: packets.PullRespPayload{
TXPK: packets.TXPK{
Imme: true,
Tmst: &tmst,
Tmms: &tmms,
Freq: 868.1,
RFCh: 0,
Powe: 14,
Expand All @@ -416,12 +416,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
Immediately: true,
TimeSinceGpsEpoch: &duration.Duration{
Seconds: 1,
},
Timestamp: tmst,
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_FSK,
Expand All @@ -432,6 +427,13 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
},
Board: 1,
Antenna: 2,
Timing: gw.DownlinkTiming_DELAY,
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
DelayTimingInfo: &gw.DelayTimingInfo{
Delay: ptypes.DurationProto(time.Second),
},
},
Context: []byte{0x00, 0x0f, 0x42, 0x40},
},
Token: 123,
},
Expand All @@ -440,9 +442,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
RandomToken: 123,
Payload: packets.PullRespPayload{
TXPK: packets.TXPK{
Imme: true,
Tmst: &tmst,
Tmms: &tmms,
Freq: 868.1,
RFCh: 0,
Powe: 14,
Expand Down
39 changes: 32 additions & 7 deletions internal/backend/semtechudp/packets/pull_resp.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ func GetPullRespPacket(protoVersion uint8, randomToken uint16, frame gw.Downlink
RandomToken: randomToken,
Payload: PullRespPayload{
TXPK: TXPK{
Imme: frame.TxInfo.Immediately,
Freq: float64(frame.TxInfo.Frequency) / 1000000,
Powe: uint8(frame.TxInfo.Power),
Modu: frame.TxInfo.Modulation.String(),
Expand Down Expand Up @@ -119,18 +118,44 @@ func GetPullRespPacket(protoVersion uint8, randomToken uint16, frame gw.Downlink
packet.Payload.TXPK.FDev = uint16(modInfo.Bitrate / 2) // TODO: is this correct?!
}

if frame.TxInfo.Timestamp != 0 {
packet.Payload.TXPK.Tmst = &frame.TxInfo.Timestamp
}
switch frame.TxInfo.Timing {
case gw.DownlinkTiming_IMMEDIATELY:
packet.Payload.TXPK.Imme = true

case gw.DownlinkTiming_DELAY:
timingInfo := frame.TxInfo.GetDelayTimingInfo()
if timingInfo == nil {
return packet, errors.New("delay_timing_info must not be nil")
}

delay, err := ptypes.Duration(timingInfo.Delay)
if err != nil {
return packet, errors.Wrap(err, "get delay duration error")
}

if frame.TxInfo.TimeSinceGpsEpoch != nil {
dur, err := ptypes.Duration(frame.TxInfo.TimeSinceGpsEpoch)
if len(frame.TxInfo.Context) < 4 {
return packet, fmt.Errorf("context must contain at least 4 bytes, got: %d", len(frame.TxInfo.Context))
}
timestamp := binary.BigEndian.Uint32(frame.TxInfo.Context[0:4])
timestamp += uint32(delay / time.Microsecond)
packet.Payload.TXPK.Tmst = &timestamp

case gw.DownlinkTiming_GPS_EPOCH:
timingInfo := frame.TxInfo.GetGpsEpochTimingInfo()
if timingInfo == nil {
return packet, errors.New("gps_epoch_timing must not be nil")
}

dur, err := ptypes.Duration(timingInfo.TimeSinceGpsEpoch)
if err != nil {
return packet, errors.Wrap(err, "parse duration error")
return packet, errors.Wrap(err, "parse time_since_gps_epoch error")
}

durMS := int64(dur / time.Millisecond)
packet.Payload.TXPK.Tmms = &durMS

default:
return packet, fmt.Errorf("unexpected downlink timing: %s", frame.TxInfo.Timing)
}

return packet, nil
Expand Down
228 changes: 226 additions & 2 deletions internal/backend/semtechudp/packets/pull_resp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package packets

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/brocaar/loraserver/api/common"
"github.com/brocaar/loraserver/api/gw"
"github.com/golang/protobuf/ptypes"
"github.com/stretchr/testify/require"
)

func TestPullResp(t *testing.T) {
assert := assert.New(t)
assert := require.New(t)

testTable := []struct {
Bytes []byte
Expand Down Expand Up @@ -38,3 +42,223 @@ func TestPullResp(t *testing.T) {
assert.Equal(test.PullRespPacket, p)
}
}

func TestGetPullRespPacket(t *testing.T) {
timestamp := uint32(2000000)
timeSinceGPSEpoch := int64(5 * time.Second / time.Millisecond)

tests := []struct {
Name string
DownlinkFrame gw.DownlinkFrame
PullRespPacket PullRespPacket
Error error
}{
{
Name: "delay timing - lora",
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_LORA,
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
LoraModulationInfo: &gw.LoRaModulationInfo{
SpreadingFactor: 12,
Bandwidth: 125,
PolarizationInversion: true,
CodeRate: "4/5",
},
},
Board: 1,
Antenna: 2,
Timing: gw.DownlinkTiming_DELAY,
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
DelayTimingInfo: &gw.DelayTimingInfo{
Delay: ptypes.DurationProto(time.Second),
},
},
Context: []byte{0x00, 0x0f, 0x42, 0x40},
},
Token: 1234,
},
PullRespPacket: PullRespPacket{
ProtocolVersion: ProtocolVersion2,
RandomToken: 1234,
Payload: PullRespPayload{
TXPK: TXPK{
Powe: 14,
Ant: 2,
Brd: 1,
Freq: 868.1,
Modu: "LORA",
Tmst: &timestamp,
DatR: DatR{
LoRa: "SF12BW125",
},
CodR: "4/5",
IPol: true,
Size: 4,
Data: []byte{0x01, 0x02, 0x03, 0x04},
},
},
},
},
{
Name: "delay timing - fsk",
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_FSK,
ModulationInfo: &gw.DownlinkTXInfo_FskModulationInfo{
FskModulationInfo: &gw.FSKModulationInfo{
Bitrate: 50000,
},
},
Board: 1,
Antenna: 2,
Timing: gw.DownlinkTiming_DELAY,
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
DelayTimingInfo: &gw.DelayTimingInfo{
Delay: ptypes.DurationProto(time.Second),
},
},
Context: []byte{0x00, 0x0f, 0x42, 0x40},
},
Token: 1234,
},
PullRespPacket: PullRespPacket{
ProtocolVersion: ProtocolVersion2,
RandomToken: 1234,
Payload: PullRespPayload{
TXPK: TXPK{
Powe: 14,
Ant: 2,
Brd: 1,
Freq: 868.1,
Modu: "FSK",
Tmst: &timestamp,
DatR: DatR{
FSK: 50000,
},
FDev: 25000,
Size: 4,
Data: []byte{0x01, 0x02, 0x03, 0x04},
},
},
},
},
{
Name: "immmediately",
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_LORA,
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
LoraModulationInfo: &gw.LoRaModulationInfo{
SpreadingFactor: 12,
Bandwidth: 125,
PolarizationInversion: true,
CodeRate: "4/5",
},
},
Board: 1,
Antenna: 2,
Timing: gw.DownlinkTiming_IMMEDIATELY,
},
Token: 1234,
},
PullRespPacket: PullRespPacket{
ProtocolVersion: ProtocolVersion2,
RandomToken: 1234,
Payload: PullRespPayload{
TXPK: TXPK{
Powe: 14,
Ant: 2,
Brd: 1,
Freq: 868.1,
Modu: "LORA",
Imme: true,
DatR: DatR{
LoRa: "SF12BW125",
},
CodR: "4/5",
IPol: true,
Size: 4,
Data: []byte{0x01, 0x02, 0x03, 0x04},
},
},
},
},
{
Name: "gps epoch",
DownlinkFrame: gw.DownlinkFrame{
PhyPayload: []byte{1, 2, 3, 4},
TxInfo: &gw.DownlinkTXInfo{
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
Frequency: 868100000,
Power: 14,
Modulation: common.Modulation_LORA,
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
LoraModulationInfo: &gw.LoRaModulationInfo{
SpreadingFactor: 12,
Bandwidth: 125,
PolarizationInversion: true,
CodeRate: "4/5",
},
},
Board: 1,
Antenna: 2,
Timing: gw.DownlinkTiming_GPS_EPOCH,
TimingInfo: &gw.DownlinkTXInfo_GpsEpochTimingInfo{
GpsEpochTimingInfo: &gw.GPSEpochTimingInfo{
TimeSinceGpsEpoch: ptypes.DurationProto(5 * time.Second),
},
},
},
Token: 1234,
},
PullRespPacket: PullRespPacket{
ProtocolVersion: ProtocolVersion2,
RandomToken: 1234,
Payload: PullRespPayload{
TXPK: TXPK{
Powe: 14,
Ant: 2,
Brd: 1,
Freq: 868.1,
Tmms: &timeSinceGPSEpoch,
Modu: "LORA",
DatR: DatR{
LoRa: "SF12BW125",
},
CodR: "4/5",
IPol: true,
Size: 4,
Data: []byte{0x01, 0x02, 0x03, 0x04},
},
},
},
},
}

for _, tst := range tests {
t.Run(tst.Name, func(t *testing.T) {
assert := require.New(t)

resp, err := GetPullRespPacket(ProtocolVersion2, 1234, tst.DownlinkFrame)
assert.Equal(tst.Error, err)
if err != nil {
return
}

assert.Equal(tst.PullRespPacket, resp)
})
}
}
Loading

0 comments on commit 08b8d7a

Please sign in to comment.