Skip to content

Commit 2aea709

Browse files
committed
Add LR-FHSS only and LoRa & LR-FHSS ADR algorithms.
1 parent 69ba076 commit 2aea709

18 files changed

+805
-249
lines changed

adr/structs.go

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ type HandleResponse struct {
8383
type UplinkMetaData struct {
8484
FCnt uint32
8585
MaxSNR float32
86+
MaxRSSI int32
8687
TXPowerIndex int
8788
GatewayCount int
8889
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/Azure/azure-service-bus-go v0.9.1
99
github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5
1010
github.com/brocaar/chirpstack-api/go/v3 v3.12.5
11-
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3
11+
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab
1212
github.com/eclipse/paho.mqtt.golang v1.2.0
1313
github.com/go-redis/redis/v8 v8.8.3
1414
github.com/gofrs/uuid v3.2.0+incompatible

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAw
8686
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
8787
github.com/brocaar/chirpstack-api/go/v3 v3.12.5 h1:sLV+zSZLUPnNCo2mf+gsw0ektbSiSHDvDn+RGs3ucgA=
8888
github.com/brocaar/chirpstack-api/go/v3 v3.12.5/go.mod h1:v8AWP19nOJK4rwJsr1+weDfpUc4UNLbRh8Eygn4Oh00=
89-
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3 h1:as8V3iH+RP5ETPyjs8e2q+YF9k8AeR/8E2bmTQL6rug=
90-
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3/go.mod h1:Vlf3gOwizqX4y3snWe/i2EqRT83HvYuwBjRu39PevW0=
89+
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab h1:sv8KWYMhLnZj7EPtZgWFl4/ZSx1f++j0Im5gYhbLuEI=
90+
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab/go.mod h1:Vlf3gOwizqX4y3snWe/i2EqRT83HvYuwBjRu39PevW0=
9191
github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw=
9292
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
9393
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e h1:V9a67dfYqPLAvzk5hMQOXYJlZ4SLIXgyKIE+ZiHzgGQ=

internal/adr/adr.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,28 @@ var (
1717
)
1818

1919
func init() {
20-
def := &DefaultHandler{}
21-
id, _ := def.ID()
22-
name, _ := def.Name()
20+
defH := &DefaultHandler{}
21+
defID, _ := defH.ID()
22+
defName, _ := defH.Name()
23+
24+
lrFHSSH := &LRFHSSHandler{}
25+
lrFHSSID, _ := lrFHSSH.ID()
26+
lrFHSSName, _ := lrFHSSH.Name()
27+
28+
loRaLRFHSSH := &LoRaLRFHSSHandler{}
29+
loraLRFHSSID, _ := loRaLRFHSSH.ID()
30+
loraLRFHSSName, _ := loRaLRFHSSH.Name()
2331

2432
handlers = map[string]adr.Handler{
25-
id: def,
33+
defID: defH,
34+
loraLRFHSSID: loRaLRFHSSH,
35+
lrFHSSID: lrFHSSH,
2636
}
2737

2838
handlerNames = map[string]string{
29-
id: name,
39+
defID: defName,
40+
loraLRFHSSID: loraLRFHSSName,
41+
lrFHSSID: lrFHSSName,
3042
}
3143
}
3244

internal/adr/default.go

+31-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package adr
22

3-
import "github.com/brocaar/chirpstack-network-server/v3/adr"
3+
import (
4+
"github.com/brocaar/chirpstack-network-server/v3/adr"
5+
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
6+
loraband "github.com/brocaar/lorawan/band"
7+
)
48

59
// DefaultHandler implements the default ADR handler.
610
type DefaultHandler struct{}
@@ -12,7 +16,7 @@ func (h *DefaultHandler) ID() (string, error) {
1216

1317
// Name returns the default name.
1418
func (h *DefaultHandler) Name() (string, error) {
15-
return "Default ADR algorithm", nil
19+
return "Default ADR algorithm (LoRa only)", nil
1620
}
1721

1822
// Handle handles the ADR request.
@@ -30,9 +34,31 @@ func (h *DefaultHandler) Handle(req adr.HandleRequest) (adr.HandleResponse, erro
3034
return resp, nil
3135
}
3236

37+
// The max DR might be configured to a non LoRa (125kHz) data-rate.
38+
// As this algorithm works on LoRa (125kHz) data-rates only, we need to
39+
// find the max LoRa (125 kHz) data-rate.
40+
maxDR := req.MaxDR
41+
maxLoRaDR := 0
42+
enabledDRs := band.Band().GetEnabledUplinkDataRates()
43+
for _, i := range enabledDRs {
44+
dr, err := band.Band().GetDataRate(i)
45+
if err != nil {
46+
return resp, err
47+
}
48+
49+
if dr.Modulation == loraband.LoRaModulation && dr.Bandwidth == 125 {
50+
maxLoRaDR = i
51+
}
52+
}
53+
54+
// Reduce to max LoRa DR.
55+
if maxDR > maxLoRaDR {
56+
maxDR = maxLoRaDR
57+
}
58+
3359
// Lower the DR only if it exceeds the max. allowed DR.
34-
if req.DR > req.MaxDR {
35-
resp.DR = req.MaxDR
60+
if req.DR > maxDR {
61+
resp.DR = maxDR
3662
}
3763

3864
// Set the new NbTrans.
@@ -50,7 +76,7 @@ func (h *DefaultHandler) Handle(req adr.HandleRequest) (adr.HandleResponse, erro
5076
return resp, nil
5177
}
5278

53-
resp.TxPowerIndex, resp.DR = h.getIdealTxPowerIndexAndDR(nStep, resp.TxPowerIndex, resp.DR, req.MaxTxPowerIndex, req.MaxDR)
79+
resp.TxPowerIndex, resp.DR = h.getIdealTxPowerIndexAndDR(nStep, resp.TxPowerIndex, resp.DR, req.MaxTxPowerIndex, maxDR)
5480

5581
return resp, nil
5682
}

internal/adr/default_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"testing"
66

77
"github.com/brocaar/chirpstack-network-server/v3/adr"
8+
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
9+
"github.com/brocaar/chirpstack-network-server/v3/internal/test"
810
"github.com/stretchr/testify/require"
911
)
1012

@@ -275,6 +277,9 @@ func TestDefaultHandler(t *testing.T) {
275277
}
276278

277279
for _, tst := range tests {
280+
conf := test.GetConfig()
281+
band.Setup(conf)
282+
278283
t.Run(tst.name, func(t *testing.T) {
279284
assert := require.New(t)
280285

internal/adr/lora_lr_fhss.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package adr
2+
3+
import (
4+
"github.com/brocaar/chirpstack-network-server/v3/adr"
5+
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
6+
)
7+
8+
// LoRaLRFHSSHandler implements a LoRa / LR-FHSS ADR handler.
9+
type LoRaLRFHSSHandler struct{}
10+
11+
// ID returns the ID.
12+
func (h *LoRaLRFHSSHandler) ID() (string, error) {
13+
return "lora_lr_fhss", nil
14+
}
15+
16+
// Name returns the name.
17+
func (h *LoRaLRFHSSHandler) Name() (string, error) {
18+
return "LoRa & LR-FHSS ADR algorithm", nil
19+
}
20+
21+
// Handle handles the ADR request.
22+
func (h *LoRaLRFHSSHandler) Handle(req adr.HandleRequest) (adr.HandleResponse, error) {
23+
resp := adr.HandleResponse{
24+
DR: req.DR,
25+
TxPowerIndex: req.TxPowerIndex,
26+
NbTrans: req.NbTrans,
27+
}
28+
29+
band := band.Band()
30+
loRaHandler := DefaultHandler{}
31+
lrFHSSHandler := LRFHSSHandler{}
32+
33+
loRaResp, err := loRaHandler.Handle(req)
34+
if err != nil {
35+
return resp, err
36+
}
37+
38+
loRaDR, err := band.GetDataRate(loRaResp.DR)
39+
if err != nil {
40+
return resp, err
41+
}
42+
43+
lrFHSSResp, err := lrFHSSHandler.Handle(req)
44+
if err != nil {
45+
return resp, err
46+
}
47+
48+
// For SF < 10, LoRa is a better option, for SF >= 10 use LR-FHSS.
49+
if loRaDR.SpreadFactor < 10 {
50+
return loRaResp, nil
51+
}
52+
53+
return lrFHSSResp, nil
54+
}

internal/adr/lora_lr_fhss_test.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package adr
2+
3+
import (
4+
"testing"
5+
6+
"github.com/brocaar/chirpstack-network-server/v3/adr"
7+
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
8+
"github.com/brocaar/chirpstack-network-server/v3/internal/test"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestLoRaLRFHSSHandler(t *testing.T) {
13+
h := &LoRaLRFHSSHandler{}
14+
15+
t.Run("ID", func(t *testing.T) {
16+
assert := require.New(t)
17+
id, err := h.ID()
18+
assert.NoError(err)
19+
assert.Equal("lora_lr_fhss", id)
20+
})
21+
22+
t.Run("Handle", func(t *testing.T) {
23+
conf := test.GetConfig()
24+
25+
// Add channel with LR-FHSS data-rate enabled.
26+
conf.NetworkServer.NetworkSettings.ExtraChannels = append(conf.NetworkServer.NetworkSettings.ExtraChannels, struct {
27+
Frequency uint32 `mapstructure:"frequency"`
28+
MinDR int `mapstructure:"min_dr"`
29+
MaxDR int `mapstructure:"max_dr"`
30+
}{
31+
Frequency: 867300000,
32+
MinDR: 10,
33+
MaxDR: 11,
34+
})
35+
band.Setup(conf)
36+
37+
tests := []struct {
38+
name string
39+
request adr.HandleRequest
40+
response adr.HandleResponse
41+
}{
42+
{
43+
name: "switch to DR 3 (LoRa)",
44+
request: adr.HandleRequest{
45+
ADR: true,
46+
DR: 0,
47+
NbTrans: 1,
48+
MaxDR: 11,
49+
RequiredSNRForDR: -20,
50+
UplinkHistory: []adr.UplinkMetaData{
51+
{
52+
MaxSNR: -10,
53+
},
54+
},
55+
},
56+
response: adr.HandleResponse{
57+
DR: 3,
58+
NbTrans: 1,
59+
},
60+
},
61+
{
62+
name: "switch to DR 3 (LoRa)",
63+
request: adr.HandleRequest{
64+
ADR: true,
65+
DR: 0,
66+
NbTrans: 3,
67+
MaxDR: 11,
68+
RequiredSNRForDR: -20,
69+
UplinkHistory: []adr.UplinkMetaData{
70+
{
71+
MaxSNR: -12,
72+
},
73+
},
74+
},
75+
response: adr.HandleResponse{
76+
DR: 10,
77+
NbTrans: 1,
78+
},
79+
},
80+
}
81+
82+
for _, tst := range tests {
83+
t.Run(tst.name, func(t *testing.T) {
84+
assert := require.New(t)
85+
86+
resp, err := h.Handle(tst.request)
87+
assert.NoError(err)
88+
assert.Equal(tst.response, resp)
89+
})
90+
}
91+
})
92+
}

0 commit comments

Comments
 (0)