Skip to content

Commit 26ef672

Browse files
committed
Add option to disable CRC status check.
1 parent 73c2f4f commit 26ef672

File tree

5 files changed

+216
-53
lines changed

5 files changed

+216
-53
lines changed

cmd/lora-gateway-bridge/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func run(c *cli.Context) error {
3838
return pubsub.UnSubscribeGatewayTX(mac)
3939
}
4040

41-
gw, err := gateway.NewBackend(c.String("udp-bind"), onNew, onDelete)
41+
gw, err := gateway.NewBackend(c.String("udp-bind"), onNew, onDelete, c.Bool("skip-crc-check"))
4242
if err != nil {
4343
log.Fatalf("could not setup gateway backend: %s", err)
4444
}
@@ -105,6 +105,11 @@ func main() {
105105
Usage: "mqtt server password (optional)",
106106
EnvVar: "MQTT_PASSWORD",
107107
},
108+
cli.BoolFlag{
109+
Name: "skip-crc-check",
110+
Usage: "skip the CRC status-check of received packets",
111+
EnvVar: "SKIP_CRC_CHECK",
112+
},
108113
cli.IntFlag{
109114
Name: "log-level",
110115
Value: 4,

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## 2.1.3
44

55
* Provide `TXPacketsReceived` and `TXPacketsEmitted` in stats.
6+
* Implement `--skip-crc-check` / `SKIP_CRC_CHECK` config flag to disable CRC
7+
checks by LoRa Gateway Bridge.
68

79
## 2.1.2
810

gateway/backend.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,18 @@ func (c *gateways) cleanup() error {
8080

8181
// Backend implements a Semtech gateway backend.
8282
type Backend struct {
83-
conn *net.UDPConn
84-
rxChan chan gw.RXPacketBytes
85-
statsChan chan gw.GatewayStatsPacket
86-
udpSendChan chan udpPacket
87-
closed bool
88-
gateways gateways
89-
wg sync.WaitGroup
83+
conn *net.UDPConn
84+
rxChan chan gw.RXPacketBytes
85+
statsChan chan gw.GatewayStatsPacket
86+
udpSendChan chan udpPacket
87+
closed bool
88+
gateways gateways
89+
wg sync.WaitGroup
90+
skipCRCCheck bool
9091
}
9192

9293
// NewBackend creates a new backend.
93-
func NewBackend(bind string, onNew func(lorawan.EUI64) error, onDelete func(lorawan.EUI64) error) (*Backend, error) {
94+
func NewBackend(bind string, onNew func(lorawan.EUI64) error, onDelete func(lorawan.EUI64) error, skipCRCCheck bool) (*Backend, error) {
9495
addr, err := net.ResolveUDPAddr("udp", bind)
9596
if err != nil {
9697
return nil, err
@@ -102,10 +103,11 @@ func NewBackend(bind string, onNew func(lorawan.EUI64) error, onDelete func(lora
102103
}
103104

104105
b := &Backend{
105-
conn: conn,
106-
rxChan: make(chan gw.RXPacketBytes),
107-
statsChan: make(chan gw.GatewayStatsPacket),
108-
udpSendChan: make(chan udpPacket),
106+
skipCRCCheck: skipCRCCheck,
107+
conn: conn,
108+
rxChan: make(chan gw.RXPacketBytes),
109+
statsChan: make(chan gw.GatewayStatsPacket),
110+
udpSendChan: make(chan udpPacket),
109111
gateways: gateways{
110112
gateways: make(map[lorawan.EUI64]gateway),
111113
onNew: onNew,
@@ -347,7 +349,7 @@ func (b *Backend) handleRXPacket(addr *net.UDPAddr, mac lorawan.EUI64, rxpk RXPK
347349
}
348350

349351
// check CRC
350-
if rxPacket.RXInfo.CRCStatus != 1 {
352+
if !b.skipCRCCheck && rxPacket.RXInfo.CRCStatus != 1 {
351353
log.WithFields(logFields).Warningf("gateway: invalid packet CRC: %d", rxPacket.RXInfo.CRCStatus)
352354
return errors.New("gateway: invalid CRC")
353355
}

gateway/backend_test.go

Lines changed: 190 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
func TestBackend(t *testing.T) {
1616
Convey("Given a new Backend binding at a random port", t, func() {
17-
backend, err := NewBackend("127.0.0.1:0", nil, nil)
17+
backend, err := NewBackend("127.0.0.1:0", nil, nil, false)
1818
So(err, ShouldBeNil)
1919

2020
backendAddr, err := net.ResolveUDPAddr("udp", backend.conn.LocalAddr().String())
@@ -91,52 +91,203 @@ func TestBackend(t *testing.T) {
9191
})
9292
})
9393

94-
Convey("When sending a PUSH_DATA packet with RXPK", func() {
95-
p := PushDataPacket{
96-
ProtocolVersion: ProtocolVersion2,
97-
RandomToken: 1234,
98-
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
99-
Payload: PushDataPayload{
100-
RXPK: []RXPK{
101-
{
102-
Time: CompactTime(time.Now().UTC()),
103-
Tmst: 708016819,
104-
Freq: 868.5,
105-
Chan: 2,
106-
RFCh: 1,
107-
Stat: 1,
108-
Modu: "LORA",
109-
DatR: DatR{LoRa: "SF7BW125"},
110-
CodR: "4/5",
111-
RSSI: -51,
112-
LSNR: 7,
113-
Size: 16,
114-
Data: "QAEBAQGAAAABVfdjR6YrSw==",
94+
Convey("Given skipCRCCheck=false", func() {
95+
backend.skipCRCCheck = false
96+
97+
Convey("When sending a PUSH_DATA packet with RXPK (CRC OK)", func() {
98+
p := PushDataPacket{
99+
ProtocolVersion: ProtocolVersion2,
100+
RandomToken: 1234,
101+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
102+
Payload: PushDataPayload{
103+
RXPK: []RXPK{
104+
{
105+
Time: CompactTime(time.Now().UTC()),
106+
Tmst: 708016819,
107+
Freq: 868.5,
108+
Chan: 2,
109+
RFCh: 1,
110+
Stat: 1,
111+
Modu: "LORA",
112+
DatR: DatR{LoRa: "SF7BW125"},
113+
CodR: "4/5",
114+
RSSI: -51,
115+
LSNR: 7,
116+
Size: 16,
117+
Data: "QAEBAQGAAAABVfdjR6YrSw==",
118+
},
115119
},
116120
},
117-
},
118-
}
119-
b, err := p.MarshalBinary()
120-
So(err, ShouldBeNil)
121-
_, err = gwConn.WriteToUDP(b, backendAddr)
122-
So(err, ShouldBeNil)
121+
}
122+
b, err := p.MarshalBinary()
123+
So(err, ShouldBeNil)
124+
_, err = gwConn.WriteToUDP(b, backendAddr)
125+
So(err, ShouldBeNil)
123126

124-
Convey("Then an ACK packet is returned", func() {
125-
buf := make([]byte, 65507)
126-
i, _, err := gwConn.ReadFromUDP(buf)
127+
Convey("Then an ACK packet is returned", func() {
128+
buf := make([]byte, 65507)
129+
i, _, err := gwConn.ReadFromUDP(buf)
130+
So(err, ShouldBeNil)
131+
var ack PushACKPacket
132+
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
133+
So(ack.RandomToken, ShouldEqual, p.RandomToken)
134+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
135+
})
136+
137+
Convey("Then the packet is returned by the RX packet channel", func() {
138+
rxPacket := <-backend.RXPacketChan()
139+
140+
rxPacket2, err := newRXPacketFromRXPK(p.GatewayMAC, p.Payload.RXPK[0])
141+
So(err, ShouldBeNil)
142+
So(rxPacket, ShouldResemble, rxPacket2)
143+
})
144+
})
145+
146+
Convey("When sending a PUSH_DATA packet with RXPK (CRC not OK)", func() {
147+
p := PushDataPacket{
148+
ProtocolVersion: ProtocolVersion2,
149+
RandomToken: 1234,
150+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
151+
Payload: PushDataPayload{
152+
RXPK: []RXPK{
153+
{
154+
Time: CompactTime(time.Now().UTC()),
155+
Tmst: 708016819,
156+
Freq: 868.5,
157+
Chan: 2,
158+
RFCh: 1,
159+
Stat: -1,
160+
Modu: "LORA",
161+
DatR: DatR{LoRa: "SF7BW125"},
162+
CodR: "4/5",
163+
RSSI: -51,
164+
LSNR: 7,
165+
Size: 16,
166+
Data: "QAEBAQGAAAABVfdjR6YrSw==",
167+
},
168+
},
169+
},
170+
}
171+
b, err := p.MarshalBinary()
127172
So(err, ShouldBeNil)
128-
var ack PushACKPacket
129-
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
130-
So(ack.RandomToken, ShouldEqual, p.RandomToken)
131-
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
173+
_, err = gwConn.WriteToUDP(b, backendAddr)
174+
So(err, ShouldBeNil)
175+
176+
Convey("Then an ACK packet is returned", func() {
177+
buf := make([]byte, 65507)
178+
i, _, err := gwConn.ReadFromUDP(buf)
179+
So(err, ShouldBeNil)
180+
var ack PushACKPacket
181+
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
182+
So(ack.RandomToken, ShouldEqual, p.RandomToken)
183+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
184+
})
185+
186+
Convey("Then the packet is not returned by the RX packet channel", func() {
187+
So(backend.RXPacketChan(), ShouldHaveLength, 0)
188+
})
132189
})
190+
})
191+
192+
Convey("Given skipCRCCheck=true", func() {
193+
backend.skipCRCCheck = true
194+
195+
Convey("When sending a PUSH_DATA packet with RXPK (CRC OK)", func() {
196+
p := PushDataPacket{
197+
ProtocolVersion: ProtocolVersion2,
198+
RandomToken: 1234,
199+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
200+
Payload: PushDataPayload{
201+
RXPK: []RXPK{
202+
{
203+
Time: CompactTime(time.Now().UTC()),
204+
Tmst: 708016819,
205+
Freq: 868.5,
206+
Chan: 2,
207+
RFCh: 1,
208+
Stat: 1,
209+
Modu: "LORA",
210+
DatR: DatR{LoRa: "SF7BW125"},
211+
CodR: "4/5",
212+
RSSI: -51,
213+
LSNR: 7,
214+
Size: 16,
215+
Data: "QAEBAQGAAAABVfdjR6YrSw==",
216+
},
217+
},
218+
},
219+
}
220+
b, err := p.MarshalBinary()
221+
So(err, ShouldBeNil)
222+
_, err = gwConn.WriteToUDP(b, backendAddr)
223+
So(err, ShouldBeNil)
224+
225+
Convey("Then an ACK packet is returned", func() {
226+
buf := make([]byte, 65507)
227+
i, _, err := gwConn.ReadFromUDP(buf)
228+
So(err, ShouldBeNil)
229+
var ack PushACKPacket
230+
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
231+
So(ack.RandomToken, ShouldEqual, p.RandomToken)
232+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
233+
})
234+
235+
Convey("Then the packet is returned by the RX packet channel", func() {
236+
rxPacket := <-backend.RXPacketChan()
133237

134-
Convey("Then the packet is returned by the RX packet channel", func() {
135-
rxPacket := <-backend.RXPacketChan()
238+
rxPacket2, err := newRXPacketFromRXPK(p.GatewayMAC, p.Payload.RXPK[0])
239+
So(err, ShouldBeNil)
240+
So(rxPacket, ShouldResemble, rxPacket2)
241+
})
242+
})
136243

137-
rxPacket2, err := newRXPacketFromRXPK(p.GatewayMAC, p.Payload.RXPK[0])
244+
Convey("When sending a PUSH_DATA packet with RXPK (CRC not OK)", func() {
245+
p := PushDataPacket{
246+
ProtocolVersion: ProtocolVersion2,
247+
RandomToken: 1234,
248+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
249+
Payload: PushDataPayload{
250+
RXPK: []RXPK{
251+
{
252+
Time: CompactTime(time.Now().UTC()),
253+
Tmst: 708016819,
254+
Freq: 868.5,
255+
Chan: 2,
256+
RFCh: 1,
257+
Stat: -1,
258+
Modu: "LORA",
259+
DatR: DatR{LoRa: "SF7BW125"},
260+
CodR: "4/5",
261+
RSSI: -51,
262+
LSNR: 7,
263+
Size: 16,
264+
Data: "QAEBAQGAAAABVfdjR6YrSw==",
265+
},
266+
},
267+
},
268+
}
269+
b, err := p.MarshalBinary()
270+
So(err, ShouldBeNil)
271+
_, err = gwConn.WriteToUDP(b, backendAddr)
138272
So(err, ShouldBeNil)
139-
So(rxPacket, ShouldResemble, rxPacket2)
273+
274+
Convey("Then an ACK packet is returned", func() {
275+
buf := make([]byte, 65507)
276+
i, _, err := gwConn.ReadFromUDP(buf)
277+
So(err, ShouldBeNil)
278+
var ack PushACKPacket
279+
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
280+
So(ack.RandomToken, ShouldEqual, p.RandomToken)
281+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
282+
})
283+
284+
Convey("Then the packet is returned by the RX packet channel", func() {
285+
rxPacket := <-backend.RXPacketChan()
286+
287+
rxPacket2, err := newRXPacketFromRXPK(p.GatewayMAC, p.Payload.RXPK[0])
288+
So(err, ShouldBeNil)
289+
So(rxPacket, ShouldResemble, rxPacket2)
290+
})
140291
})
141292
})
142293

packaging/deb/default

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ MQTT_PASSWORD=
1212

1313
# debug=5, info=4, warning=3, error=2, fatal=1, panic=0 (default: 4)
1414
LOG_LEVEL=4
15+
16+
# skip the CRC status-check of received packets
17+
# SKIP_CRC_CHECK=true

0 commit comments

Comments
 (0)