4
4
"crypto/rand"
5
5
"crypto/tls"
6
6
"crypto/x509"
7
+ "encoding/base64"
7
8
"encoding/binary"
8
9
"encoding/json"
9
10
"fmt"
@@ -20,9 +21,9 @@ import (
20
21
"github.com/pkg/errors"
21
22
log "github.com/sirupsen/logrus"
22
23
24
+ "github.com/brocaar/chirpstack-api/go/v3/gw"
23
25
"github.com/brocaar/chirpstack-gateway-bridge/internal/backend/basicstation/structs"
24
26
"github.com/brocaar/chirpstack-gateway-bridge/internal/config"
25
- "github.com/brocaar/chirpstack-api/go/v3/gw"
26
27
"github.com/brocaar/lorawan"
27
28
"github.com/brocaar/lorawan/band"
28
29
)
@@ -48,9 +49,10 @@ type Backend struct {
48
49
49
50
gateways gateways
50
51
51
- downlinkTXAckChan chan gw.DownlinkTXAck
52
- uplinkFrameChan chan gw.UplinkFrame
53
- gatewayStatsChan chan gw.GatewayStats
52
+ downlinkTXAckChan chan gw.DownlinkTXAck
53
+ uplinkFrameChan chan gw.UplinkFrame
54
+ gatewayStatsChan chan gw.GatewayStats
55
+ rawPacketForwarderEventChan chan gw.RawPacketForwarderEvent
54
56
55
57
band band.Band
56
58
region band.Name
@@ -77,9 +79,10 @@ func NewBackend(conf config.Config) (*Backend, error) {
77
79
disconnectChan : make (chan lorawan.EUI64 ),
78
80
},
79
81
80
- downlinkTXAckChan : make (chan gw.DownlinkTXAck ),
81
- uplinkFrameChan : make (chan gw.UplinkFrame ),
82
- gatewayStatsChan : make (chan gw.GatewayStats ),
82
+ downlinkTXAckChan : make (chan gw.DownlinkTXAck ),
83
+ uplinkFrameChan : make (chan gw.UplinkFrame ),
84
+ gatewayStatsChan : make (chan gw.GatewayStats ),
85
+ rawPacketForwarderEventChan : make (chan gw.RawPacketForwarderEvent ),
83
86
84
87
pingInterval : conf .Backend .BasicStation .PingInterval ,
85
88
readTimeout : conf .Backend .BasicStation .ReadTimeout ,
@@ -210,6 +213,11 @@ func (b *Backend) GetDisconnectChan() chan lorawan.EUI64 {
210
213
return b .gateways .disconnectChan
211
214
}
212
215
216
+ // GetRawPacketForwarderEventChan returns the raw packet-forwarder command channel.
217
+ func (b * Backend ) GetRawPacketForwarderEventChan () chan gw.RawPacketForwarderEvent {
218
+ return b .rawPacketForwarderEventChan
219
+ }
220
+
213
221
func (b * Backend ) SendDownlinkFrame (df gw.DownlinkFrame ) error {
214
222
b .Lock ()
215
223
defer b .Unlock ()
@@ -269,6 +277,36 @@ func (b *Backend) ApplyConfiguration(gwConfig gw.GatewayConfiguration) error {
269
277
return nil
270
278
}
271
279
280
+ // RawPacketForwarderCommand sends the given raw command to the packet-forwarder.
281
+ func (b * Backend ) RawPacketForwarderCommand (pl gw.RawPacketForwarderCommand ) error {
282
+ var gatewayID lorawan.EUI64
283
+ var rawID uuid.UUID
284
+
285
+ copy (gatewayID [:], pl .GatewayId )
286
+ copy (rawID [:], pl .RawId )
287
+
288
+ if len (pl .Payload ) == 0 {
289
+ return errors .New ("raw packet-forwarder command payload is empty" )
290
+ }
291
+
292
+ mt := websocket .BinaryMessage
293
+ if strings .HasPrefix (string (pl .Payload ), "{" ) {
294
+ mt = websocket .TextMessage
295
+ }
296
+
297
+ websocketSendCounter ("raw" ).Inc ()
298
+ if err := b .sendRawToGateway (gatewayID , mt , pl .Payload ); err != nil {
299
+ return errors .Wrap (err , "send raw packet-forwarder command to gateway error" )
300
+ }
301
+
302
+ log .WithFields (log.Fields {
303
+ "gateway_id" : gatewayID ,
304
+ "raw_id" : rawID ,
305
+ }).Info ("backend/basicstation: raw packet-forwarder command sent to gateway" )
306
+
307
+ return nil
308
+ }
309
+
272
310
// Close closes the backend.
273
311
func (b * Backend ) Close () error {
274
312
b .isClosed = true
@@ -302,8 +340,14 @@ func (b *Backend) handleRouterInfo(r *http.Request, c *websocket.Conn) {
302
340
}
303
341
}
304
342
343
+ bb , err := json .Marshal (resp )
344
+ if err != nil {
345
+ log .WithError (err ).Error ("backend/basicstation: marshal json error" )
346
+ return
347
+ }
348
+
305
349
c .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
306
- if err := c .WriteJSON ( resp ); err != nil {
350
+ if err := c .WriteMessage ( websocket . TextMessage , bb ); err != nil {
307
351
log .WithError (err ).Error ("backend/basicstation: websocket send message error" )
308
352
return
309
353
}
@@ -367,7 +411,7 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
367
411
368
412
// receive data
369
413
for {
370
- _ , msg , err := c .ReadMessage ()
414
+ mt , msg , err := c .ReadMessage ()
371
415
if err != nil {
372
416
if websocket .IsUnexpectedCloseError (err , websocket .CloseNormalClosure , websocket .CloseGoingAway , websocket .CloseAbnormalClosure ) {
373
417
log .WithField ("gateway_id" , gatewayID ).WithError (err ).Error ("backend/basicstation: read message error" )
@@ -378,6 +422,16 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
378
422
// reset the read deadline as the Basic Station doesn't respond to PONG messages (yet)
379
423
c .SetReadDeadline (time .Now ().Add (b .readTimeout ))
380
424
425
+ if mt == websocket .BinaryMessage {
426
+ log .WithFields (log.Fields {
427
+ "gateway_id" : gatewayID ,
428
+ "message_base64" : base64 .StdEncoding .EncodeToString (msg ),
429
+ }).Debug ("backend/basicstation: binary message received" )
430
+
431
+ b .handleRawPacketForwarderEvent (gatewayID , msg )
432
+ continue
433
+ }
434
+
381
435
log .WithFields (log.Fields {
382
436
"gateway_id" : gatewayID ,
383
437
"message" : string (msg ),
@@ -458,11 +512,7 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
458
512
}
459
513
b .handleDownlinkTransmittedMessage (gatewayID , pl )
460
514
default :
461
- log .WithFields (log.Fields {
462
- "message_type" : msgType ,
463
- "gateway_id" : gatewayID ,
464
- "payload" : string (msg ),
465
- }).Warning ("backend/basicstation: unexpected message-type" )
515
+ b .handleRawPacketForwarderEvent (gatewayID , msg )
466
516
}
467
517
}
468
518
}
@@ -616,14 +666,56 @@ func (b *Backend) handleUplinkDataFrame(gatewayID lorawan.EUI64, v structs.Uplin
616
666
b .uplinkFrameChan <- uplinkFrame
617
667
}
618
668
669
+ func (b * Backend ) handleRawPacketForwarderEvent (gatewayID lorawan.EUI64 , pl []byte ) {
670
+ rawID , err := uuid .NewV4 ()
671
+ if err != nil {
672
+ log .WithError (err ).WithFields (log.Fields {
673
+ "gateway_id" : gatewayID ,
674
+ }).Error ("backend/basicstation: get random raw id error" )
675
+ return
676
+ }
677
+
678
+ rawEvent := gw.RawPacketForwarderEvent {
679
+ GatewayId : gatewayID [:],
680
+ RawId : rawID [:],
681
+ Payload : pl ,
682
+ }
683
+
684
+ log .WithFields (log.Fields {
685
+ "gateway_id" : gatewayID ,
686
+ "raw_id" : rawID ,
687
+ }).Info ("backend/basicstation: raw packet-forwarder event received" )
688
+
689
+ b .rawPacketForwarderEventChan <- rawEvent
690
+ }
691
+
619
692
func (b * Backend ) sendToGateway (gatewayID lorawan.EUI64 , v interface {}) error {
620
693
gw , err := b .gateways .get (gatewayID )
621
694
if err != nil {
622
695
return errors .Wrap (err , "get gateway error" )
623
696
}
624
697
698
+ bb , err := json .Marshal (v )
699
+ if err != nil {
700
+ return errors .Wrap (err , "marshal json error" )
701
+ }
702
+
703
+ gw .conn .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
704
+ if err := gw .conn .WriteMessage (websocket .TextMessage , bb ); err != nil {
705
+ return errors .Wrap (err , "send message to gateway error" )
706
+ }
707
+
708
+ return nil
709
+ }
710
+
711
+ func (b * Backend ) sendRawToGateway (gatewayID lorawan.EUI64 , messageType int , data []byte ) error {
712
+ gw , err := b .gateways .get (gatewayID )
713
+ if err != nil {
714
+ return errors .Wrap (err , "get gateway error" )
715
+ }
716
+
625
717
gw .conn .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
626
- if err := gw .conn .WriteJSON ( v ); err != nil {
718
+ if err := gw .conn .WriteMessage ( messageType , data ); err != nil {
627
719
return errors .Wrap (err , "send message to gateway error" )
628
720
}
629
721
0 commit comments