Skip to content

Commit 08b8d7a

Browse files
committed
Update Semtech UDP backend to use new timing.
1 parent b9124a4 commit 08b8d7a

File tree

5 files changed

+294
-30
lines changed

5 files changed

+294
-30
lines changed

internal/backend/semtechudp/backend_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ func (ts *BackendTestSuite) TestPushData() {
295295
LoraSnr: 7,
296296
Channel: 2,
297297
RfChain: 1,
298+
Context: []byte{0x2a, 0x33, 0x7a, 0xb3},
298299
},
299300
},
300301
},
@@ -341,8 +342,7 @@ func (ts *BackendTestSuite) TestPushData() {
341342
func (ts *BackendTestSuite) TestSendDownlinkFrame() {
342343
assert := require.New(ts.T())
343344

344-
tmst := uint32(1234567)
345-
tmms := int64(time.Second / time.Millisecond)
345+
tmst := uint32(2000000)
346346

347347
testTable := []struct {
348348
Name string
@@ -364,12 +364,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
364364
DownlinkFrame: gw.DownlinkFrame{
365365
PhyPayload: []byte{1, 2, 3, 4},
366366
TxInfo: &gw.DownlinkTXInfo{
367-
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
368-
Immediately: true,
369-
TimeSinceGpsEpoch: &duration.Duration{
370-
Seconds: 1,
371-
},
372-
Timestamp: tmst,
367+
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
373368
Frequency: 868100000,
374369
Power: 14,
375370
Modulation: common.Modulation_LORA,
@@ -381,8 +376,15 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
381376
PolarizationInversion: true,
382377
},
383378
},
379+
Timing: gw.DownlinkTiming_DELAY,
380+
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
381+
DelayTimingInfo: &gw.DelayTimingInfo{
382+
Delay: ptypes.DurationProto(time.Second),
383+
},
384+
},
384385
Board: 1,
385386
Antenna: 2,
387+
Context: []byte{0x00, 0x0f, 0x42, 0x40},
386388
},
387389
Token: 123,
388390
},
@@ -391,9 +393,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
391393
RandomToken: 123,
392394
Payload: packets.PullRespPayload{
393395
TXPK: packets.TXPK{
394-
Imme: true,
395396
Tmst: &tmst,
396-
Tmms: &tmms,
397397
Freq: 868.1,
398398
RFCh: 0,
399399
Powe: 14,
@@ -416,12 +416,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
416416
DownlinkFrame: gw.DownlinkFrame{
417417
PhyPayload: []byte{1, 2, 3, 4},
418418
TxInfo: &gw.DownlinkTXInfo{
419-
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
420-
Immediately: true,
421-
TimeSinceGpsEpoch: &duration.Duration{
422-
Seconds: 1,
423-
},
424-
Timestamp: tmst,
419+
GatewayId: []byte{1, 2, 3, 4, 5, 6, 7, 8},
425420
Frequency: 868100000,
426421
Power: 14,
427422
Modulation: common.Modulation_FSK,
@@ -432,6 +427,13 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
432427
},
433428
Board: 1,
434429
Antenna: 2,
430+
Timing: gw.DownlinkTiming_DELAY,
431+
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
432+
DelayTimingInfo: &gw.DelayTimingInfo{
433+
Delay: ptypes.DurationProto(time.Second),
434+
},
435+
},
436+
Context: []byte{0x00, 0x0f, 0x42, 0x40},
435437
},
436438
Token: 123,
437439
},
@@ -440,9 +442,7 @@ func (ts *BackendTestSuite) TestSendDownlinkFrame() {
440442
RandomToken: 123,
441443
Payload: packets.PullRespPayload{
442444
TXPK: packets.TXPK{
443-
Imme: true,
444445
Tmst: &tmst,
445-
Tmms: &tmms,
446446
Freq: 868.1,
447447
RFCh: 0,
448448
Powe: 14,

internal/backend/semtechudp/packets/pull_resp.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ func GetPullRespPacket(protoVersion uint8, randomToken uint16, frame gw.Downlink
8888
RandomToken: randomToken,
8989
Payload: PullRespPayload{
9090
TXPK: TXPK{
91-
Imme: frame.TxInfo.Immediately,
9291
Freq: float64(frame.TxInfo.Frequency) / 1000000,
9392
Powe: uint8(frame.TxInfo.Power),
9493
Modu: frame.TxInfo.Modulation.String(),
@@ -119,18 +118,44 @@ func GetPullRespPacket(protoVersion uint8, randomToken uint16, frame gw.Downlink
119118
packet.Payload.TXPK.FDev = uint16(modInfo.Bitrate / 2) // TODO: is this correct?!
120119
}
121120

122-
if frame.TxInfo.Timestamp != 0 {
123-
packet.Payload.TXPK.Tmst = &frame.TxInfo.Timestamp
124-
}
121+
switch frame.TxInfo.Timing {
122+
case gw.DownlinkTiming_IMMEDIATELY:
123+
packet.Payload.TXPK.Imme = true
124+
125+
case gw.DownlinkTiming_DELAY:
126+
timingInfo := frame.TxInfo.GetDelayTimingInfo()
127+
if timingInfo == nil {
128+
return packet, errors.New("delay_timing_info must not be nil")
129+
}
130+
131+
delay, err := ptypes.Duration(timingInfo.Delay)
132+
if err != nil {
133+
return packet, errors.Wrap(err, "get delay duration error")
134+
}
125135

126-
if frame.TxInfo.TimeSinceGpsEpoch != nil {
127-
dur, err := ptypes.Duration(frame.TxInfo.TimeSinceGpsEpoch)
136+
if len(frame.TxInfo.Context) < 4 {
137+
return packet, fmt.Errorf("context must contain at least 4 bytes, got: %d", len(frame.TxInfo.Context))
138+
}
139+
timestamp := binary.BigEndian.Uint32(frame.TxInfo.Context[0:4])
140+
timestamp += uint32(delay / time.Microsecond)
141+
packet.Payload.TXPK.Tmst = &timestamp
142+
143+
case gw.DownlinkTiming_GPS_EPOCH:
144+
timingInfo := frame.TxInfo.GetGpsEpochTimingInfo()
145+
if timingInfo == nil {
146+
return packet, errors.New("gps_epoch_timing must not be nil")
147+
}
148+
149+
dur, err := ptypes.Duration(timingInfo.TimeSinceGpsEpoch)
128150
if err != nil {
129-
return packet, errors.Wrap(err, "parse duration error")
151+
return packet, errors.Wrap(err, "parse time_since_gps_epoch error")
130152
}
131153

132154
durMS := int64(dur / time.Millisecond)
133155
packet.Payload.TXPK.Tmms = &durMS
156+
157+
default:
158+
return packet, fmt.Errorf("unexpected downlink timing: %s", frame.TxInfo.Timing)
134159
}
135160

136161
return packet, nil

internal/backend/semtechudp/packets/pull_resp_test.go

Lines changed: 226 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package packets
22

33
import (
44
"testing"
5+
"time"
56

6-
"github.com/stretchr/testify/assert"
7+
"github.com/brocaar/loraserver/api/common"
8+
"github.com/brocaar/loraserver/api/gw"
9+
"github.com/golang/protobuf/ptypes"
10+
"github.com/stretchr/testify/require"
711
)
812

913
func TestPullResp(t *testing.T) {
10-
assert := assert.New(t)
14+
assert := require.New(t)
1115

1216
testTable := []struct {
1317
Bytes []byte
@@ -38,3 +42,223 @@ func TestPullResp(t *testing.T) {
3842
assert.Equal(test.PullRespPacket, p)
3943
}
4044
}
45+
46+
func TestGetPullRespPacket(t *testing.T) {
47+
timestamp := uint32(2000000)
48+
timeSinceGPSEpoch := int64(5 * time.Second / time.Millisecond)
49+
50+
tests := []struct {
51+
Name string
52+
DownlinkFrame gw.DownlinkFrame
53+
PullRespPacket PullRespPacket
54+
Error error
55+
}{
56+
{
57+
Name: "delay timing - lora",
58+
DownlinkFrame: gw.DownlinkFrame{
59+
PhyPayload: []byte{1, 2, 3, 4},
60+
TxInfo: &gw.DownlinkTXInfo{
61+
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
62+
Frequency: 868100000,
63+
Power: 14,
64+
Modulation: common.Modulation_LORA,
65+
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
66+
LoraModulationInfo: &gw.LoRaModulationInfo{
67+
SpreadingFactor: 12,
68+
Bandwidth: 125,
69+
PolarizationInversion: true,
70+
CodeRate: "4/5",
71+
},
72+
},
73+
Board: 1,
74+
Antenna: 2,
75+
Timing: gw.DownlinkTiming_DELAY,
76+
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
77+
DelayTimingInfo: &gw.DelayTimingInfo{
78+
Delay: ptypes.DurationProto(time.Second),
79+
},
80+
},
81+
Context: []byte{0x00, 0x0f, 0x42, 0x40},
82+
},
83+
Token: 1234,
84+
},
85+
PullRespPacket: PullRespPacket{
86+
ProtocolVersion: ProtocolVersion2,
87+
RandomToken: 1234,
88+
Payload: PullRespPayload{
89+
TXPK: TXPK{
90+
Powe: 14,
91+
Ant: 2,
92+
Brd: 1,
93+
Freq: 868.1,
94+
Modu: "LORA",
95+
Tmst: &timestamp,
96+
DatR: DatR{
97+
LoRa: "SF12BW125",
98+
},
99+
CodR: "4/5",
100+
IPol: true,
101+
Size: 4,
102+
Data: []byte{0x01, 0x02, 0x03, 0x04},
103+
},
104+
},
105+
},
106+
},
107+
{
108+
Name: "delay timing - fsk",
109+
DownlinkFrame: gw.DownlinkFrame{
110+
PhyPayload: []byte{1, 2, 3, 4},
111+
TxInfo: &gw.DownlinkTXInfo{
112+
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
113+
Frequency: 868100000,
114+
Power: 14,
115+
Modulation: common.Modulation_FSK,
116+
ModulationInfo: &gw.DownlinkTXInfo_FskModulationInfo{
117+
FskModulationInfo: &gw.FSKModulationInfo{
118+
Bitrate: 50000,
119+
},
120+
},
121+
Board: 1,
122+
Antenna: 2,
123+
Timing: gw.DownlinkTiming_DELAY,
124+
TimingInfo: &gw.DownlinkTXInfo_DelayTimingInfo{
125+
DelayTimingInfo: &gw.DelayTimingInfo{
126+
Delay: ptypes.DurationProto(time.Second),
127+
},
128+
},
129+
Context: []byte{0x00, 0x0f, 0x42, 0x40},
130+
},
131+
Token: 1234,
132+
},
133+
PullRespPacket: PullRespPacket{
134+
ProtocolVersion: ProtocolVersion2,
135+
RandomToken: 1234,
136+
Payload: PullRespPayload{
137+
TXPK: TXPK{
138+
Powe: 14,
139+
Ant: 2,
140+
Brd: 1,
141+
Freq: 868.1,
142+
Modu: "FSK",
143+
Tmst: &timestamp,
144+
DatR: DatR{
145+
FSK: 50000,
146+
},
147+
FDev: 25000,
148+
Size: 4,
149+
Data: []byte{0x01, 0x02, 0x03, 0x04},
150+
},
151+
},
152+
},
153+
},
154+
{
155+
Name: "immmediately",
156+
DownlinkFrame: gw.DownlinkFrame{
157+
PhyPayload: []byte{1, 2, 3, 4},
158+
TxInfo: &gw.DownlinkTXInfo{
159+
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
160+
Frequency: 868100000,
161+
Power: 14,
162+
Modulation: common.Modulation_LORA,
163+
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
164+
LoraModulationInfo: &gw.LoRaModulationInfo{
165+
SpreadingFactor: 12,
166+
Bandwidth: 125,
167+
PolarizationInversion: true,
168+
CodeRate: "4/5",
169+
},
170+
},
171+
Board: 1,
172+
Antenna: 2,
173+
Timing: gw.DownlinkTiming_IMMEDIATELY,
174+
},
175+
Token: 1234,
176+
},
177+
PullRespPacket: PullRespPacket{
178+
ProtocolVersion: ProtocolVersion2,
179+
RandomToken: 1234,
180+
Payload: PullRespPayload{
181+
TXPK: TXPK{
182+
Powe: 14,
183+
Ant: 2,
184+
Brd: 1,
185+
Freq: 868.1,
186+
Modu: "LORA",
187+
Imme: true,
188+
DatR: DatR{
189+
LoRa: "SF12BW125",
190+
},
191+
CodR: "4/5",
192+
IPol: true,
193+
Size: 4,
194+
Data: []byte{0x01, 0x02, 0x03, 0x04},
195+
},
196+
},
197+
},
198+
},
199+
{
200+
Name: "gps epoch",
201+
DownlinkFrame: gw.DownlinkFrame{
202+
PhyPayload: []byte{1, 2, 3, 4},
203+
TxInfo: &gw.DownlinkTXInfo{
204+
GatewayId: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
205+
Frequency: 868100000,
206+
Power: 14,
207+
Modulation: common.Modulation_LORA,
208+
ModulationInfo: &gw.DownlinkTXInfo_LoraModulationInfo{
209+
LoraModulationInfo: &gw.LoRaModulationInfo{
210+
SpreadingFactor: 12,
211+
Bandwidth: 125,
212+
PolarizationInversion: true,
213+
CodeRate: "4/5",
214+
},
215+
},
216+
Board: 1,
217+
Antenna: 2,
218+
Timing: gw.DownlinkTiming_GPS_EPOCH,
219+
TimingInfo: &gw.DownlinkTXInfo_GpsEpochTimingInfo{
220+
GpsEpochTimingInfo: &gw.GPSEpochTimingInfo{
221+
TimeSinceGpsEpoch: ptypes.DurationProto(5 * time.Second),
222+
},
223+
},
224+
},
225+
Token: 1234,
226+
},
227+
PullRespPacket: PullRespPacket{
228+
ProtocolVersion: ProtocolVersion2,
229+
RandomToken: 1234,
230+
Payload: PullRespPayload{
231+
TXPK: TXPK{
232+
Powe: 14,
233+
Ant: 2,
234+
Brd: 1,
235+
Freq: 868.1,
236+
Tmms: &timeSinceGPSEpoch,
237+
Modu: "LORA",
238+
DatR: DatR{
239+
LoRa: "SF12BW125",
240+
},
241+
CodR: "4/5",
242+
IPol: true,
243+
Size: 4,
244+
Data: []byte{0x01, 0x02, 0x03, 0x04},
245+
},
246+
},
247+
},
248+
},
249+
}
250+
251+
for _, tst := range tests {
252+
t.Run(tst.Name, func(t *testing.T) {
253+
assert := require.New(t)
254+
255+
resp, err := GetPullRespPacket(ProtocolVersion2, 1234, tst.DownlinkFrame)
256+
assert.Equal(tst.Error, err)
257+
if err != nil {
258+
return
259+
}
260+
261+
assert.Equal(tst.PullRespPacket, resp)
262+
})
263+
}
264+
}

0 commit comments

Comments
 (0)