Skip to content

Commit

Permalink
Add LR-FHSS only and LoRa & LR-FHSS ADR algorithms.
Browse files Browse the repository at this point in the history
  • Loading branch information
brocaar committed Feb 18, 2022
1 parent 69ba076 commit 2aea709
Show file tree
Hide file tree
Showing 18 changed files with 805 additions and 249 deletions.
1 change: 1 addition & 0 deletions adr/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type HandleResponse struct {
type UplinkMetaData struct {
FCnt uint32
MaxSNR float32
MaxRSSI int32
TXPowerIndex int
GatewayCount int
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/Azure/azure-service-bus-go v0.9.1
github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5
github.com/brocaar/chirpstack-api/go/v3 v3.12.5
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/go-redis/redis/v8 v8.8.3
github.com/gofrs/uuid v3.2.0+incompatible
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAw
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/brocaar/chirpstack-api/go/v3 v3.12.5 h1:sLV+zSZLUPnNCo2mf+gsw0ektbSiSHDvDn+RGs3ucgA=
github.com/brocaar/chirpstack-api/go/v3 v3.12.5/go.mod h1:v8AWP19nOJK4rwJsr1+weDfpUc4UNLbRh8Eygn4Oh00=
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3 h1:as8V3iH+RP5ETPyjs8e2q+YF9k8AeR/8E2bmTQL6rug=
github.com/brocaar/lorawan v0.0.0-20211213100234-63df6954a2f3/go.mod h1:Vlf3gOwizqX4y3snWe/i2EqRT83HvYuwBjRu39PevW0=
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab h1:sv8KWYMhLnZj7EPtZgWFl4/ZSx1f++j0Im5gYhbLuEI=
github.com/brocaar/lorawan v0.0.0-20220207095711-d675789e16ab/go.mod h1:Vlf3gOwizqX4y3snWe/i2EqRT83HvYuwBjRu39PevW0=
github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw=
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e h1:V9a67dfYqPLAvzk5hMQOXYJlZ4SLIXgyKIE+ZiHzgGQ=
Expand Down
22 changes: 17 additions & 5 deletions internal/adr/adr.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,28 @@ var (
)

func init() {
def := &DefaultHandler{}
id, _ := def.ID()
name, _ := def.Name()
defH := &DefaultHandler{}
defID, _ := defH.ID()
defName, _ := defH.Name()

lrFHSSH := &LRFHSSHandler{}
lrFHSSID, _ := lrFHSSH.ID()
lrFHSSName, _ := lrFHSSH.Name()

loRaLRFHSSH := &LoRaLRFHSSHandler{}
loraLRFHSSID, _ := loRaLRFHSSH.ID()
loraLRFHSSName, _ := loRaLRFHSSH.Name()

handlers = map[string]adr.Handler{
id: def,
defID: defH,
loraLRFHSSID: loRaLRFHSSH,
lrFHSSID: lrFHSSH,
}

handlerNames = map[string]string{
id: name,
defID: defName,
loraLRFHSSID: loraLRFHSSName,
lrFHSSID: lrFHSSName,
}
}

Expand Down
36 changes: 31 additions & 5 deletions internal/adr/default.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package adr

import "github.com/brocaar/chirpstack-network-server/v3/adr"
import (
"github.com/brocaar/chirpstack-network-server/v3/adr"
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
loraband "github.com/brocaar/lorawan/band"
)

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

// Name returns the default name.
func (h *DefaultHandler) Name() (string, error) {
return "Default ADR algorithm", nil
return "Default ADR algorithm (LoRa only)", nil
}

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

// The max DR might be configured to a non LoRa (125kHz) data-rate.
// As this algorithm works on LoRa (125kHz) data-rates only, we need to
// find the max LoRa (125 kHz) data-rate.
maxDR := req.MaxDR
maxLoRaDR := 0
enabledDRs := band.Band().GetEnabledUplinkDataRates()
for _, i := range enabledDRs {
dr, err := band.Band().GetDataRate(i)
if err != nil {
return resp, err
}

if dr.Modulation == loraband.LoRaModulation && dr.Bandwidth == 125 {
maxLoRaDR = i
}
}

// Reduce to max LoRa DR.
if maxDR > maxLoRaDR {
maxDR = maxLoRaDR
}

// Lower the DR only if it exceeds the max. allowed DR.
if req.DR > req.MaxDR {
resp.DR = req.MaxDR
if req.DR > maxDR {
resp.DR = maxDR
}

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

resp.TxPowerIndex, resp.DR = h.getIdealTxPowerIndexAndDR(nStep, resp.TxPowerIndex, resp.DR, req.MaxTxPowerIndex, req.MaxDR)
resp.TxPowerIndex, resp.DR = h.getIdealTxPowerIndexAndDR(nStep, resp.TxPowerIndex, resp.DR, req.MaxTxPowerIndex, maxDR)

return resp, nil
}
Expand Down
5 changes: 5 additions & 0 deletions internal/adr/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"testing"

"github.com/brocaar/chirpstack-network-server/v3/adr"
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
"github.com/brocaar/chirpstack-network-server/v3/internal/test"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -275,6 +277,9 @@ func TestDefaultHandler(t *testing.T) {
}

for _, tst := range tests {
conf := test.GetConfig()
band.Setup(conf)

t.Run(tst.name, func(t *testing.T) {
assert := require.New(t)

Expand Down
54 changes: 54 additions & 0 deletions internal/adr/lora_lr_fhss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package adr

import (
"github.com/brocaar/chirpstack-network-server/v3/adr"
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
)

// LoRaLRFHSSHandler implements a LoRa / LR-FHSS ADR handler.
type LoRaLRFHSSHandler struct{}

// ID returns the ID.
func (h *LoRaLRFHSSHandler) ID() (string, error) {
return "lora_lr_fhss", nil
}

// Name returns the name.
func (h *LoRaLRFHSSHandler) Name() (string, error) {
return "LoRa & LR-FHSS ADR algorithm", nil
}

// Handle handles the ADR request.
func (h *LoRaLRFHSSHandler) Handle(req adr.HandleRequest) (adr.HandleResponse, error) {
resp := adr.HandleResponse{
DR: req.DR,
TxPowerIndex: req.TxPowerIndex,
NbTrans: req.NbTrans,
}

band := band.Band()
loRaHandler := DefaultHandler{}
lrFHSSHandler := LRFHSSHandler{}

loRaResp, err := loRaHandler.Handle(req)
if err != nil {
return resp, err
}

loRaDR, err := band.GetDataRate(loRaResp.DR)
if err != nil {
return resp, err
}

lrFHSSResp, err := lrFHSSHandler.Handle(req)
if err != nil {
return resp, err
}

// For SF < 10, LoRa is a better option, for SF >= 10 use LR-FHSS.
if loRaDR.SpreadFactor < 10 {
return loRaResp, nil
}

return lrFHSSResp, nil
}
92 changes: 92 additions & 0 deletions internal/adr/lora_lr_fhss_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package adr

import (
"testing"

"github.com/brocaar/chirpstack-network-server/v3/adr"
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
"github.com/brocaar/chirpstack-network-server/v3/internal/test"
"github.com/stretchr/testify/require"
)

func TestLoRaLRFHSSHandler(t *testing.T) {
h := &LoRaLRFHSSHandler{}

t.Run("ID", func(t *testing.T) {
assert := require.New(t)
id, err := h.ID()
assert.NoError(err)
assert.Equal("lora_lr_fhss", id)
})

t.Run("Handle", func(t *testing.T) {
conf := test.GetConfig()

// Add channel with LR-FHSS data-rate enabled.
conf.NetworkServer.NetworkSettings.ExtraChannels = append(conf.NetworkServer.NetworkSettings.ExtraChannels, struct {
Frequency uint32 `mapstructure:"frequency"`
MinDR int `mapstructure:"min_dr"`
MaxDR int `mapstructure:"max_dr"`
}{
Frequency: 867300000,
MinDR: 10,
MaxDR: 11,
})
band.Setup(conf)

tests := []struct {
name string
request adr.HandleRequest
response adr.HandleResponse
}{
{
name: "switch to DR 3 (LoRa)",
request: adr.HandleRequest{
ADR: true,
DR: 0,
NbTrans: 1,
MaxDR: 11,
RequiredSNRForDR: -20,
UplinkHistory: []adr.UplinkMetaData{
{
MaxSNR: -10,
},
},
},
response: adr.HandleResponse{
DR: 3,
NbTrans: 1,
},
},
{
name: "switch to DR 3 (LoRa)",
request: adr.HandleRequest{
ADR: true,
DR: 0,
NbTrans: 3,
MaxDR: 11,
RequiredSNRForDR: -20,
UplinkHistory: []adr.UplinkMetaData{
{
MaxSNR: -12,
},
},
},
response: adr.HandleResponse{
DR: 10,
NbTrans: 1,
},
},
}

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

resp, err := h.Handle(tst.request)
assert.NoError(err)
assert.Equal(tst.response, resp)
})
}
})
}
Loading

0 comments on commit 2aea709

Please sign in to comment.