-
-
Notifications
You must be signed in to change notification settings - Fork 544
/
link_adr.go
150 lines (124 loc) · 4.85 KB
/
link_adr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package maccommand
import (
"context"
"fmt"
"github.com/brocaar/chirpstack-network-server/v3/internal/band"
"github.com/brocaar/chirpstack-network-server/v3/internal/logging"
"github.com/brocaar/chirpstack-network-server/v3/internal/storage"
"github.com/brocaar/lorawan"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
// handleLinkADRAns handles the ack of an ADR request
func handleLinkADRAns(ctx context.Context, ds *storage.DeviceSession, block storage.MACCommandBlock, pendingBlock *storage.MACCommandBlock) ([]storage.MACCommandBlock, error) {
if len(block.MACCommands) == 0 {
return nil, errors.New("at least 1 mac-command expected, got none")
}
if pendingBlock == nil || len(pendingBlock.MACCommands) == 0 {
return nil, errors.New("expected pending mac-command")
}
channelMaskACK := true
dataRateACK := true
powerACK := true
for i := range block.MACCommands {
pl, ok := block.MACCommands[i].Payload.(*lorawan.LinkADRAnsPayload)
if !ok {
return nil, fmt.Errorf("expected *lorawan.LinkADRAnsPayload, got %T", block.MACCommands[i].Payload)
}
if !pl.ChannelMaskACK {
channelMaskACK = false
}
if !pl.DataRateACK {
dataRateACK = false
}
if !pl.PowerACK {
powerACK = false
}
}
var linkADRPayloads []lorawan.LinkADRReqPayload
for i := range pendingBlock.MACCommands {
linkADRPayloads = append(linkADRPayloads, *pendingBlock.MACCommands[i].Payload.(*lorawan.LinkADRReqPayload))
}
// as we're sending the same txpower and nbrep for each channel we
// take the last one
adrReq := linkADRPayloads[len(linkADRPayloads)-1]
if channelMaskACK && dataRateACK && powerACK {
// The device acked all request (channel-mask, data-rate and power),
// in this case we update the device-session with all the requested
// modifcations.
// reset the error counter
delete(ds.MACCommandErrorCount, lorawan.LinkADRAns)
chans, err := band.Band().GetEnabledUplinkChannelIndicesForLinkADRReqPayloads(ds.EnabledUplinkChannels, linkADRPayloads)
if err != nil {
return nil, errors.Wrap(err, "get enalbed channels for link_adr_req payloads error")
}
ds.TXPowerIndex = int(adrReq.TXPower)
ds.DR = int(adrReq.DataRate)
ds.NbTrans = adrReq.Redundancy.NbRep
ds.EnabledUplinkChannels = chans
log.WithFields(log.Fields{
"dev_eui": ds.DevEUI,
"tx_power_idx": ds.TXPowerIndex,
"dr": adrReq.DataRate,
"nb_trans": adrReq.Redundancy.NbRep,
"enabled_channels": chans,
"ctx_id": ctx.Value(logging.ContextIDKey),
}).Info("link_adr request acknowledged")
} else if !ds.ADR && channelMaskACK {
// In case the device has ADR disabled, at least it must acknowledge the
// channel-mask. It does not have to acknowledge the other parameters.
// See 4.3.1.1 of LoRaWAN 1.0.4 specs.
// reset the error counter
delete(ds.MACCommandErrorCount, lorawan.LinkADRAns)
chans, err := band.Band().GetEnabledUplinkChannelIndicesForLinkADRReqPayloads(ds.EnabledUplinkChannels, linkADRPayloads)
if err != nil {
return nil, errors.Wrap(err, "get enalbed channels for link_adr_req payloads error")
}
ds.EnabledUplinkChannels = chans
ds.NbTrans = adrReq.Redundancy.NbRep // It is assumed that this is accepted, as there is no explicit status bit for this?
if dataRateACK {
ds.DR = int(adrReq.DataRate)
}
if powerACK {
ds.TXPowerIndex = int(adrReq.TXPower)
}
log.WithFields(log.Fields{
"dev_eui": ds.DevEUI,
"tx_power_idx": ds.TXPowerIndex,
"dr": adrReq.DataRate,
"nb_trans": adrReq.Redundancy.NbRep,
"enabled_channels": chans,
"ctx_id": ctx.Value(logging.ContextIDKey),
}).Info("link_adr request acknowledged (device has ADR disabled)")
} else {
// increase the error counter
ds.MACCommandErrorCount[lorawan.LinkADRAns]++
// TODO: remove workaround once all RN2483 nodes have the issue below
// fixed.
//
// This is a workaround for the RN2483 firmware (1.0.3) which sends
// a nACK on TXPower 0 (this is incorrect behaviour, following the
// specs). It should ACK and operate at its maximum possible power
// when TXPower 0 is not supported. See also section 5.2 in the
// LoRaWAN specs.
if !powerACK && adrReq.TXPower == 0 {
ds.TXPowerIndex = 1
ds.MinSupportedTXPowerIndex = 1
}
// It is possible that the node does not support all TXPower
// indices. In this case we set the MaxSupportedTXPowerIndex
// to the request - 1. If that index is not supported, it will
// be lowered by 1 at the next nACK.
if !powerACK && adrReq.TXPower > 0 {
ds.MaxSupportedTXPowerIndex = int(adrReq.TXPower) - 1
}
log.WithFields(log.Fields{
"dev_eui": ds.DevEUI,
"channel_mask_ack": channelMaskACK,
"data_rate_ack": dataRateACK,
"power_ack": powerACK,
"ctx_id": ctx.Value(logging.ContextIDKey),
}).Warning("link_adr request not acknowledged")
}
return nil, nil
}