MultiTech / mDot_Channel_Plans

The channel plans in this library can be used as starting points for new channel plans and used as a reference for implementation.

Information

To use source version of a channel plan, first remove the Channel Plans folder from libmDot-Custom library.

Not all plans are complete to LoRaWAN specifications.

AS923 and KR920 have the default channels defined and can accept in channels in the Join Accept message or from New Channel MAC commands.

Channel Set must match those expected by the network server in order for ADR to work

AS923 regional settings can be adjusted by the network server using Tx Param Setup MAC command to set max EIRP and dwell time for uplinks.

Committer:
Jason Reiss
Date:
Tue Feb 07 09:00:25 2017 -0600
Revision:
13:996f1663d12e
Parent:
12:2e8fda56093f
Child:
14:5bbcd92d635a
Fix P2P in dynamic plans, channel 0 was being used instead of the set frequency

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jason Reiss 13:996f1663d12e 1 /**********************************************************************
Jason Reiss 13:996f1663d12e 2 * COPYRIGHT 2016 MULTI-TECH SYSTEMS, INC.
Jason Reiss 13:996f1663d12e 3 *
Jason Reiss 13:996f1663d12e 4 * ALL RIGHTS RESERVED BY AND FOR THE EXCLUSIVE BENEFIT OF
Jason Reiss 13:996f1663d12e 5 * MULTI-TECH SYSTEMS, INC.
Jason Reiss 13:996f1663d12e 6 *
Jason Reiss 13:996f1663d12e 7 * MULTI-TECH SYSTEMS, INC. - CONFIDENTIAL AND PROPRIETARY
Jason Reiss 13:996f1663d12e 8 * INFORMATION AND/OR TRADE SECRET.
Jason Reiss 13:996f1663d12e 9 *
Jason Reiss 13:996f1663d12e 10 * NOTICE: ALL CODE, PROGRAM, INFORMATION, SCRIPT, INSTRUCTION,
Jason Reiss 13:996f1663d12e 11 * DATA, AND COMMENT HEREIN IS AND SHALL REMAIN THE CONFIDENTIAL
Jason Reiss 13:996f1663d12e 12 * INFORMATION AND PROPERTY OF MULTI-TECH SYSTEMS, INC.
Jason Reiss 13:996f1663d12e 13 * USE AND DISCLOSURE THEREOF, EXCEPT AS STRICTLY AUTHORIZED IN A
Jason Reiss 13:996f1663d12e 14 * WRITTEN AGREEMENT SIGNED BY MULTI-TECH SYSTEMS, INC. IS PROHIBITED.
Jason Reiss 13:996f1663d12e 15 *
Jason Reiss 13:996f1663d12e 16 ***********************************************************************/
Jason Reiss 13:996f1663d12e 17
Jason Reiss 13:996f1663d12e 18 #include "CustomChannelPlan_AS923.h"
Jason Reiss 13:996f1663d12e 19 #include "limits.h"
Jason Reiss 13:996f1663d12e 20
Jason Reiss 13:996f1663d12e 21 using namespace lora;
Jason Reiss 13:996f1663d12e 22
Jason Reiss 13:996f1663d12e 23 const uint8_t CustomChannelPlan_AS923::AS923_TX_POWERS[] = { 20, 14, 11, 8, 5, 2 };
Jason Reiss 13:996f1663d12e 24 const uint8_t CustomChannelPlan_AS923::AS923_RADIO_POWERS[] = { 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20 };
Jason Reiss 13:996f1663d12e 25 const uint8_t CustomChannelPlan_AS923::AS923_MAX_PAYLOAD_SIZE[] = { 51, 51, 51, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0, 0 };
Jason Reiss 13:996f1663d12e 26 const uint8_t CustomChannelPlan_AS923::AS923_MAX_PAYLOAD_SIZE_REPEATER[] = { 51, 51, 51, 115, 222, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0 };
Jason Reiss 13:996f1663d12e 27 const uint8_t CustomChannelPlan_AS923::AS923_MAX_PAYLOAD_SIZE_400[] = { 0, 0, 19, 61, 133, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0, 0 };
Jason Reiss 13:996f1663d12e 28 const uint8_t CustomChannelPlan_AS923::AS923_MAX_PAYLOAD_SIZE_REPEATER_400[] = { 0, 0, 19, 61, 133, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0 };
Jason Reiss 13:996f1663d12e 29
Jason Reiss 13:996f1663d12e 30 const uint8_t MAX_ERP_VALUES[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 };
Jason Reiss 13:996f1663d12e 31
Jason Reiss 13:996f1663d12e 32 CustomChannelPlan_AS923::CustomChannelPlan_AS923(SxRadio& radio, Settings& settings)
Jason Reiss 13:996f1663d12e 33 :
Jason Reiss 13:996f1663d12e 34 ChannelPlan(radio, settings)
Jason Reiss 13:996f1663d12e 35 {
Jason Reiss 13:996f1663d12e 36
Jason Reiss 13:996f1663d12e 37 }
Jason Reiss 13:996f1663d12e 38
Jason Reiss 13:996f1663d12e 39 CustomChannelPlan_AS923::~CustomChannelPlan_AS923() {
Jason Reiss 13:996f1663d12e 40
Jason Reiss 13:996f1663d12e 41 }
Jason Reiss 13:996f1663d12e 42
Jason Reiss 13:996f1663d12e 43 void CustomChannelPlan_AS923::Init() {
Jason Reiss 13:996f1663d12e 44
Jason Reiss 13:996f1663d12e 45 _datarates.clear();
Jason Reiss 13:996f1663d12e 46 _channels.clear();
Jason Reiss 13:996f1663d12e 47 _dutyBands.clear();
Jason Reiss 13:996f1663d12e 48
Jason Reiss 13:996f1663d12e 49 DutyBand band;
Jason Reiss 13:996f1663d12e 50
Jason Reiss 13:996f1663d12e 51 band.Index = 0;
Jason Reiss 13:996f1663d12e 52 band.DutyCycle = 0;
Jason Reiss 13:996f1663d12e 53
Jason Reiss 13:996f1663d12e 54 Datarate dr;
Jason Reiss 13:996f1663d12e 55
Jason Reiss 13:996f1663d12e 56 _type = DYNAMIC;
Jason Reiss 13:996f1663d12e 57 _planName = "AS923";
Jason Reiss 13:996f1663d12e 58 _maxTxPower = 36;
Jason Reiss 13:996f1663d12e 59 _minTxPower = 2;
Jason Reiss 13:996f1663d12e 60
Jason Reiss 13:996f1663d12e 61 _minFrequency = 920000000;
Jason Reiss 13:996f1663d12e 62 _maxFrequency = 928000000;
Jason Reiss 13:996f1663d12e 63
Jason Reiss 13:996f1663d12e 64 TX_POWERS = AS923_TX_POWERS;
Jason Reiss 13:996f1663d12e 65 RADIO_POWERS = AS923_RADIO_POWERS;
Jason Reiss 13:996f1663d12e 66 MAX_PAYLOAD_SIZE = AS923_MAX_PAYLOAD_SIZE;
Jason Reiss 13:996f1663d12e 67 MAX_PAYLOAD_SIZE_REPEATER = AS923_MAX_PAYLOAD_SIZE_REPEATER;
Jason Reiss 13:996f1663d12e 68
Jason Reiss 13:996f1663d12e 69 _minDatarate = 0;
Jason Reiss 13:996f1663d12e 70 _maxDatarate = 7;
Jason Reiss 13:996f1663d12e 71
Jason Reiss 13:996f1663d12e 72 _minRx2Datarate = DR_0;
Jason Reiss 13:996f1663d12e 73 _maxRx2Datarate = DR_7;
Jason Reiss 13:996f1663d12e 74
Jason Reiss 13:996f1663d12e 75 _minDatarateOffset = 0;
Jason Reiss 13:996f1663d12e 76 _maxDatarateOffset = 7;
Jason Reiss 13:996f1663d12e 77
Jason Reiss 13:996f1663d12e 78 _numChans125k = 16;
Jason Reiss 13:996f1663d12e 79 _numChans500k = 0;
Jason Reiss 13:996f1663d12e 80
Jason Reiss 13:996f1663d12e 81 _settings.Session.Rx2Frequency = 923200000;
Jason Reiss 13:996f1663d12e 82 _settings.Session.Rx2DatarateIndex = DR_2;
Jason Reiss 13:996f1663d12e 83 _settings.Session.Max_EIRP = 20;
Jason Reiss 13:996f1663d12e 84
Jason Reiss 13:996f1663d12e 85 logInfo("Initialize datarates...");
Jason Reiss 13:996f1663d12e 86
Jason Reiss 13:996f1663d12e 87 dr.SpreadingFactor = SF_12;
Jason Reiss 13:996f1663d12e 88
Jason Reiss 13:996f1663d12e 89 // Add DR0-5
Jason Reiss 13:996f1663d12e 90 while (dr.SpreadingFactor >= SF_7) {
Jason Reiss 13:996f1663d12e 91 AddDatarate(-1, dr);
Jason Reiss 13:996f1663d12e 92 dr.SpreadingFactor--;
Jason Reiss 13:996f1663d12e 93 dr.Index++;
Jason Reiss 13:996f1663d12e 94 }
Jason Reiss 13:996f1663d12e 95
Jason Reiss 13:996f1663d12e 96 // Add DR6
Jason Reiss 13:996f1663d12e 97 dr.SpreadingFactor = SF_7;
Jason Reiss 13:996f1663d12e 98 dr.Bandwidth = BW_250;
Jason Reiss 13:996f1663d12e 99 AddDatarate(-1, dr);
Jason Reiss 13:996f1663d12e 100 dr.Index++;
Jason Reiss 13:996f1663d12e 101
Jason Reiss 13:996f1663d12e 102 // Add DR7
Jason Reiss 13:996f1663d12e 103 dr.SpreadingFactor = SF_FSK;
Jason Reiss 13:996f1663d12e 104 dr.Bandwidth = BW_FSK;
Jason Reiss 13:996f1663d12e 105 dr.PreambleLength = 10;
Jason Reiss 13:996f1663d12e 106 dr.Coderate = 0;
Jason Reiss 13:996f1663d12e 107 AddDatarate(-1, dr);
Jason Reiss 13:996f1663d12e 108 dr.Index++;
Jason Reiss 13:996f1663d12e 109
Jason Reiss 13:996f1663d12e 110 _maxDatarate = DR_7;
Jason Reiss 13:996f1663d12e 111
Jason Reiss 13:996f1663d12e 112 // Skip DR8-15 RFU
Jason Reiss 13:996f1663d12e 113 dr.SpreadingFactor = SF_INVALID;
Jason Reiss 13:996f1663d12e 114 while (dr.Index++ < DR_15) {
Jason Reiss 13:996f1663d12e 115 AddDatarate(-1, dr);
Jason Reiss 13:996f1663d12e 116 }
Jason Reiss 13:996f1663d12e 117
Jason Reiss 13:996f1663d12e 118 _settings.Session.TxDatarate = 0;
Jason Reiss 13:996f1663d12e 119
Jason Reiss 13:996f1663d12e 120 logInfo("Initialize channels...");
Jason Reiss 13:996f1663d12e 121
Jason Reiss 13:996f1663d12e 122 Channel chan;
Jason Reiss 13:996f1663d12e 123 chan.DrRange.Fields.Min = DR_0;
Jason Reiss 13:996f1663d12e 124 chan.DrRange.Fields.Max = DR_5;
Jason Reiss 13:996f1663d12e 125 chan.Index = 0;
Jason Reiss 13:996f1663d12e 126 chan.Frequency = 923200000;
Jason Reiss 13:996f1663d12e 127 SetNumberOfChannels(16);
Jason Reiss 13:996f1663d12e 128
Jason Reiss 13:996f1663d12e 129 for (uint8_t i = 0; i < 2; i++) {
Jason Reiss 13:996f1663d12e 130 AddChannel(i, chan);
Jason Reiss 13:996f1663d12e 131 chan.Index++;
Jason Reiss 13:996f1663d12e 132 chan.Frequency += 200000;
Jason Reiss 13:996f1663d12e 133 }
Jason Reiss 13:996f1663d12e 134
Jason Reiss 13:996f1663d12e 135 chan.DrRange.Value = 0;
Jason Reiss 13:996f1663d12e 136 chan.Frequency = 0;
Jason Reiss 13:996f1663d12e 137
Jason Reiss 13:996f1663d12e 138 for (uint8_t i = 2; i < 16; i++) {
Jason Reiss 13:996f1663d12e 139 AddChannel(i, chan);
Jason Reiss 13:996f1663d12e 140 chan.Index++;
Jason Reiss 13:996f1663d12e 141 }
Jason Reiss 13:996f1663d12e 142
Jason Reiss 13:996f1663d12e 143 SetChannelMask(0, 0x03);
Jason Reiss 13:996f1663d12e 144
Jason Reiss 13:996f1663d12e 145
Jason Reiss 13:996f1663d12e 146 // Add downlink channel defaults
Jason Reiss 13:996f1663d12e 147 chan.Index = 0;
Jason Reiss 13:996f1663d12e 148 _dlChannels.resize(16);
Jason Reiss 13:996f1663d12e 149 for (uint8_t i = 0; i < 16; i++) {
Jason Reiss 13:996f1663d12e 150 AddDownlinkChannel(i, chan);
Jason Reiss 13:996f1663d12e 151 chan.Index++;
Jason Reiss 13:996f1663d12e 152 }
Jason Reiss 13:996f1663d12e 153
Jason Reiss 13:996f1663d12e 154 band.Index = 0;
Jason Reiss 13:996f1663d12e 155 band.FrequencyMin = _minFrequency;
Jason Reiss 13:996f1663d12e 156 band.FrequencyMax = _maxFrequency;
Jason Reiss 13:996f1663d12e 157 band.PowerMax = 14;
Jason Reiss 13:996f1663d12e 158 band.TimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 159
Jason Reiss 13:996f1663d12e 160 // Disable duty-cycle limits
Jason Reiss 13:996f1663d12e 161 band.DutyCycle = 0;
Jason Reiss 13:996f1663d12e 162
Jason Reiss 13:996f1663d12e 163 AddDutyBand(-1, band);
Jason Reiss 13:996f1663d12e 164 }
Jason Reiss 13:996f1663d12e 165
Jason Reiss 13:996f1663d12e 166 uint8_t CustomChannelPlan_AS923::AddChannel(int8_t index, Channel channel) {
Jason Reiss 13:996f1663d12e 167 logTrace("Add Channel %d : %lu : %02x %d", index, channel.Frequency, channel.DrRange.Value, _channels.size());
Jason Reiss 13:996f1663d12e 168
Jason Reiss 13:996f1663d12e 169 assert(index < (int) _channels.size());
Jason Reiss 13:996f1663d12e 170
Jason Reiss 13:996f1663d12e 171 if (index >= 0) {
Jason Reiss 13:996f1663d12e 172 _channels[index] = channel;
Jason Reiss 13:996f1663d12e 173 } else {
Jason Reiss 13:996f1663d12e 174 _channels.push_back(channel);
Jason Reiss 13:996f1663d12e 175 }
Jason Reiss 13:996f1663d12e 176
Jason Reiss 13:996f1663d12e 177 return LORA_OK;
Jason Reiss 13:996f1663d12e 178 }
Jason Reiss 13:996f1663d12e 179
Jason Reiss 13:996f1663d12e 180 uint8_t CustomChannelPlan_AS923::HandleJoinAccept(const uint8_t* buffer, uint8_t size) {
Jason Reiss 13:996f1663d12e 181
Jason Reiss 13:996f1663d12e 182 if (size == 33) {
Jason Reiss 13:996f1663d12e 183 Channel ch;
Jason Reiss 13:996f1663d12e 184 int index = 2;
Jason Reiss 13:996f1663d12e 185 for (int i = 13; i < size - 5; i += 3) {
Jason Reiss 13:996f1663d12e 186
Jason Reiss 13:996f1663d12e 187 ch.Frequency = ((buffer[i]) | (buffer[i + 1] << 8) | (buffer[i + 2] << 16)) * 100u;
Jason Reiss 13:996f1663d12e 188
Jason Reiss 13:996f1663d12e 189 if (ch.Frequency > 0) {
Jason Reiss 13:996f1663d12e 190 ch.Index = index;
Jason Reiss 13:996f1663d12e 191 ch.DrRange.Fields.Min = static_cast<int8_t>(DR_0);
Jason Reiss 13:996f1663d12e 192 ch.DrRange.Fields.Max = static_cast<int8_t>(DR_5);
Jason Reiss 13:996f1663d12e 193 AddChannel(index, ch);
Jason Reiss 13:996f1663d12e 194
Jason Reiss 13:996f1663d12e 195 if (GetDutyBand(ch.Frequency) > -1)
Jason Reiss 13:996f1663d12e 196 _channelMask[0] |= (1 << index);
Jason Reiss 13:996f1663d12e 197 else
Jason Reiss 13:996f1663d12e 198 _channelMask[0] |= ~(1 << index);
Jason Reiss 13:996f1663d12e 199
Jason Reiss 13:996f1663d12e 200 index += 1;
Jason Reiss 13:996f1663d12e 201 }
Jason Reiss 13:996f1663d12e 202 }
Jason Reiss 13:996f1663d12e 203 }
Jason Reiss 13:996f1663d12e 204
Jason Reiss 13:996f1663d12e 205 return LORA_OK;
Jason Reiss 13:996f1663d12e 206 }
Jason Reiss 13:996f1663d12e 207
Jason Reiss 13:996f1663d12e 208 uint8_t CustomChannelPlan_AS923::SetTxConfig() {
Jason Reiss 13:996f1663d12e 209
Jason Reiss 13:996f1663d12e 210 logInfo("Configure radio for TX");
Jason Reiss 13:996f1663d12e 211
Jason Reiss 13:996f1663d12e 212 Datarate txDr = GetDatarate(_settings.Session.TxDatarate);
Jason Reiss 13:996f1663d12e 213 int8_t max_pwr = _settings.Session.Max_EIRP;
Jason Reiss 13:996f1663d12e 214
Jason Reiss 13:996f1663d12e 215 int8_t pwr = 0;
Jason Reiss 13:996f1663d12e 216
Jason Reiss 13:996f1663d12e 217 pwr = std::min < int8_t > (_settings.Session.TxPower, (max_pwr - _settings.Network.AntennaGain));
Jason Reiss 13:996f1663d12e 218
Jason Reiss 13:996f1663d12e 219 for (int i = 20; i >= 0; i--) {
Jason Reiss 13:996f1663d12e 220 if (RADIO_POWERS[i] <= pwr) {
Jason Reiss 13:996f1663d12e 221 pwr = i;
Jason Reiss 13:996f1663d12e 222 break;
Jason Reiss 13:996f1663d12e 223 }
Jason Reiss 13:996f1663d12e 224 if (i == 0) {
Jason Reiss 13:996f1663d12e 225 pwr = i;
Jason Reiss 13:996f1663d12e 226 }
Jason Reiss 13:996f1663d12e 227 }
Jason Reiss 13:996f1663d12e 228
Jason Reiss 13:996f1663d12e 229 logDebug("Session pwr: %d ant: %d max: %d", _settings.Session.TxPower, _settings.Network.AntennaGain, max_pwr);
Jason Reiss 13:996f1663d12e 230 logDebug("Radio Power index: %d output: %d total: %d", pwr, RADIO_POWERS[pwr], RADIO_POWERS[pwr] + _settings.Network.AntennaGain);
Jason Reiss 13:996f1663d12e 231
Jason Reiss 13:996f1663d12e 232 uint32_t bw = txDr.Bandwidth;
Jason Reiss 13:996f1663d12e 233 uint32_t sf = txDr.SpreadingFactor;
Jason Reiss 13:996f1663d12e 234 uint8_t cr = txDr.Coderate;
Jason Reiss 13:996f1663d12e 235 uint8_t pl = txDr.PreambleLength;
Jason Reiss 13:996f1663d12e 236 uint16_t fdev = 0;
Jason Reiss 13:996f1663d12e 237 bool crc = txDr.Crc;
Jason Reiss 13:996f1663d12e 238 bool iq = txDr.TxIQ;
Jason Reiss 13:996f1663d12e 239
Jason Reiss 13:996f1663d12e 240 if (_settings.Network.DisableCRC == true)
Jason Reiss 13:996f1663d12e 241 crc = false;
Jason Reiss 13:996f1663d12e 242
Jason Reiss 13:996f1663d12e 243 SxRadio::RadioModems_t modem = SxRadio::MODEM_LORA;
Jason Reiss 13:996f1663d12e 244
Jason Reiss 13:996f1663d12e 245 if (sf == SF_FSK) {
Jason Reiss 13:996f1663d12e 246 modem = SxRadio::MODEM_FSK;
Jason Reiss 13:996f1663d12e 247 sf = 50e3;
Jason Reiss 13:996f1663d12e 248 fdev = 25e3;
Jason Reiss 13:996f1663d12e 249 bw = 0;
Jason Reiss 13:996f1663d12e 250 }
Jason Reiss 13:996f1663d12e 251
Jason Reiss 13:996f1663d12e 252 _radio.SetTxConfig(modem, pwr, fdev, bw, sf, cr, pl, false, crc, false, 0, iq, 3e3);
Jason Reiss 13:996f1663d12e 253
Jason Reiss 13:996f1663d12e 254 logDebug("TX PWR: %u DR: %u SF: %u BW: %u CR: %u PL: %u CRC: %d IQ: %d", pwr, txDr.Index, sf, bw, cr, pl, crc, iq);
Jason Reiss 13:996f1663d12e 255
Jason Reiss 13:996f1663d12e 256 return LORA_OK;
Jason Reiss 13:996f1663d12e 257 }
Jason Reiss 13:996f1663d12e 258
Jason Reiss 13:996f1663d12e 259 uint8_t CustomChannelPlan_AS923::SetRxConfig(uint8_t window, bool continuous) {
Jason Reiss 13:996f1663d12e 260
Jason Reiss 13:996f1663d12e 261 RxWindow rxw = GetRxWindow(window);
Jason Reiss 13:996f1663d12e 262
Jason Reiss 13:996f1663d12e 263 if (_dlChannels[_txChannel].Frequency != 0)
Jason Reiss 13:996f1663d12e 264 _radio.SetChannel(_dlChannels[_txChannel].Frequency);
Jason Reiss 13:996f1663d12e 265 else
Jason Reiss 13:996f1663d12e 266 _radio.SetChannel(rxw.Frequency);
Jason Reiss 13:996f1663d12e 267
Jason Reiss 13:996f1663d12e 268 Datarate rxDr = GetDatarate(rxw.DatarateIndex);
Jason Reiss 13:996f1663d12e 269 uint32_t bw = rxDr.Bandwidth;
Jason Reiss 13:996f1663d12e 270 uint32_t sf = rxDr.SpreadingFactor;
Jason Reiss 13:996f1663d12e 271 uint8_t cr = rxDr.Coderate;
Jason Reiss 13:996f1663d12e 272 uint8_t pl = rxDr.PreambleLength;
Jason Reiss 13:996f1663d12e 273 uint16_t sto = rxDr.SymbolTimeout();
Jason Reiss 13:996f1663d12e 274 uint32_t afc = 0;
Jason Reiss 13:996f1663d12e 275 bool crc = rxDr.Crc;
Jason Reiss 13:996f1663d12e 276
Jason Reiss 13:996f1663d12e 277 if (_settings.Network.DisableCRC == true)
Jason Reiss 13:996f1663d12e 278 crc = false;
Jason Reiss 13:996f1663d12e 279
Jason Reiss 13:996f1663d12e 280 Datarate txDr = GetDatarate(_settings.Session.TxDatarate);
Jason Reiss 13:996f1663d12e 281 bool iq = txDr.RxIQ;
Jason Reiss 13:996f1663d12e 282
Jason Reiss 13:996f1663d12e 283 if (P2PEnabled()) {
Jason Reiss 13:996f1663d12e 284 iq = txDr.TxIQ;
Jason Reiss 13:996f1663d12e 285 }
Jason Reiss 13:996f1663d12e 286
Jason Reiss 13:996f1663d12e 287 SxRadio::RadioModems_t modem = SxRadio::MODEM_LORA;
Jason Reiss 13:996f1663d12e 288
Jason Reiss 13:996f1663d12e 289 if (sf == SF_FSK) {
Jason Reiss 13:996f1663d12e 290 modem = SxRadio::MODEM_FSK;
Jason Reiss 13:996f1663d12e 291 sf = 50e3;
Jason Reiss 13:996f1663d12e 292 cr = 0;
Jason Reiss 13:996f1663d12e 293 bw = 50e3;
Jason Reiss 13:996f1663d12e 294 afc = 83333;
Jason Reiss 13:996f1663d12e 295 iq = false;
Jason Reiss 13:996f1663d12e 296 }
Jason Reiss 13:996f1663d12e 297
Jason Reiss 13:996f1663d12e 298 // Disable printf's to actually receive packets, printing to debug may mess up the timing
Jason Reiss 13:996f1663d12e 299 // logTrace("Configure radio for RX%d on freq: %lu", window, rxw.Frequency);
Jason Reiss 13:996f1663d12e 300 // logTrace("RX SF: %u BW: %u CR: %u PL: %u STO: %u CRC: %d IQ: %d", sf, bw, cr, pl, sto, crc, iq);
Jason Reiss 13:996f1663d12e 301
Jason Reiss 13:996f1663d12e 302 _radio.SetRxConfig(modem, bw, sf, cr, afc, pl, sto, false, 0, crc, false, 0, iq, continuous);
Jason Reiss 13:996f1663d12e 303
Jason Reiss 13:996f1663d12e 304 return LORA_OK;
Jason Reiss 13:996f1663d12e 305 }
Jason Reiss 13:996f1663d12e 306
Jason Reiss 13:996f1663d12e 307 Channel CustomChannelPlan_AS923::GetChannel(int8_t index) {
Jason Reiss 13:996f1663d12e 308 Channel chan;
Jason Reiss 13:996f1663d12e 309 memset(&chan, 0, sizeof(Channel));
Jason Reiss 13:996f1663d12e 310
Jason Reiss 13:996f1663d12e 311 chan = _channels[index];
Jason Reiss 13:996f1663d12e 312
Jason Reiss 13:996f1663d12e 313 return chan;
Jason Reiss 13:996f1663d12e 314 }
Jason Reiss 13:996f1663d12e 315
Jason Reiss 13:996f1663d12e 316 uint8_t CustomChannelPlan_AS923::SetChannelGroup(uint8_t group) {
Jason Reiss 13:996f1663d12e 317 return LORA_OK;
Jason Reiss 13:996f1663d12e 318 }
Jason Reiss 13:996f1663d12e 319
Jason Reiss 13:996f1663d12e 320 void CustomChannelPlan_AS923::LogRxWindow(uint8_t wnd) {
Jason Reiss 13:996f1663d12e 321
Jason Reiss 13:996f1663d12e 322 RxWindow rxw = GetRxWindow(wnd);
Jason Reiss 13:996f1663d12e 323 Datarate rxDr = GetDatarate(rxw.DatarateIndex);
Jason Reiss 13:996f1663d12e 324 uint8_t bw = rxDr.Bandwidth;
Jason Reiss 13:996f1663d12e 325 uint8_t sf = rxDr.SpreadingFactor;
Jason Reiss 13:996f1663d12e 326 uint8_t cr = rxDr.Coderate;
Jason Reiss 13:996f1663d12e 327 uint8_t pl = rxDr.PreambleLength;
Jason Reiss 13:996f1663d12e 328 uint16_t sto = rxDr.SymbolTimeout();
Jason Reiss 13:996f1663d12e 329 bool crc = rxDr.Crc;
Jason Reiss 13:996f1663d12e 330 bool iq = GetTxDatarate().RxIQ;
Jason Reiss 13:996f1663d12e 331 uint32_t freq = rxw.Frequency;
Jason Reiss 13:996f1663d12e 332
Jason Reiss 13:996f1663d12e 333 if (_dlChannels[_txChannel].Frequency != 0)
Jason Reiss 13:996f1663d12e 334 freq = _dlChannels[_txChannel].Frequency;
Jason Reiss 13:996f1663d12e 335
Jason Reiss 13:996f1663d12e 336 logTrace("RX%d on freq: %lu", wnd, freq);
Jason Reiss 13:996f1663d12e 337 logTrace("RX DR: %u SF: %u BW: %u CR: %u PL: %u STO: %u CRC: %d IQ: %d", rxDr.Index, sf, bw, cr, pl, sto, crc, iq);
Jason Reiss 13:996f1663d12e 338 }
Jason Reiss 13:996f1663d12e 339
Jason Reiss 13:996f1663d12e 340 uint8_t CustomChannelPlan_AS923::GetMaxPayloadSize() {
Jason Reiss 13:996f1663d12e 341 if (_settings.Session.UplinkDwelltime == 1) {
Jason Reiss 13:996f1663d12e 342 if (_settings.Network.RepeaterMode)
Jason Reiss 13:996f1663d12e 343 return AS923_MAX_PAYLOAD_SIZE_REPEATER_400[_settings.Session.TxDatarate];
Jason Reiss 13:996f1663d12e 344 else
Jason Reiss 13:996f1663d12e 345 return AS923_MAX_PAYLOAD_SIZE_400[_settings.Session.TxDatarate];
Jason Reiss 13:996f1663d12e 346 } else {
Jason Reiss 13:996f1663d12e 347 if (_settings.Network.RepeaterMode)
Jason Reiss 13:996f1663d12e 348 return MAX_PAYLOAD_SIZE_REPEATER[_settings.Session.TxDatarate];
Jason Reiss 13:996f1663d12e 349 else
Jason Reiss 13:996f1663d12e 350 return MAX_PAYLOAD_SIZE[_settings.Session.TxDatarate];
Jason Reiss 13:996f1663d12e 351 }
Jason Reiss 13:996f1663d12e 352 }
Jason Reiss 13:996f1663d12e 353
Jason Reiss 13:996f1663d12e 354 RxWindow CustomChannelPlan_AS923::GetRxWindow(uint8_t window) {
Jason Reiss 13:996f1663d12e 355 RxWindow rxw;
Jason Reiss 13:996f1663d12e 356 int index = 0;
Jason Reiss 13:996f1663d12e 357
Jason Reiss 13:996f1663d12e 358 if (P2PEnabled()) {
Jason Reiss 13:996f1663d12e 359 rxw.Frequency = _settings.Network.TxFrequency;
Jason Reiss 13:996f1663d12e 360 index = _settings.Session.TxDatarate;
Jason Reiss 13:996f1663d12e 361 } else {
Jason Reiss 13:996f1663d12e 362 if (window == 1) {
Jason Reiss 13:996f1663d12e 363 // Use same frequency as TX
Jason Reiss 13:996f1663d12e 364 rxw.Frequency = _channels[_txChannel].Frequency;
Jason Reiss 13:996f1663d12e 365
Jason Reiss 13:996f1663d12e 366 if (_settings.Session.Rx1DatarateOffset >= 6) {
Jason Reiss 13:996f1663d12e 367 index = _settings.Session.TxDatarate + (_settings.Session.Rx1DatarateOffset == 6 ? 1 : 2);
Jason Reiss 13:996f1663d12e 368 index = std::min<int>(index, _maxDatarate);
Jason Reiss 13:996f1663d12e 369 } else if (_settings.Session.TxDatarate > _settings.Session.Rx1DatarateOffset) {
Jason Reiss 13:996f1663d12e 370 index = _settings.Session.TxDatarate - _settings.Session.Rx1DatarateOffset;
Jason Reiss 13:996f1663d12e 371 } else {
Jason Reiss 13:996f1663d12e 372 index = 0;
Jason Reiss 13:996f1663d12e 373 }
Jason Reiss 13:996f1663d12e 374
Jason Reiss 13:996f1663d12e 375 } else {
Jason Reiss 13:996f1663d12e 376 // Use session RX2 frequency
Jason Reiss 13:996f1663d12e 377 rxw.Frequency = _settings.Session.Rx2Frequency;
Jason Reiss 13:996f1663d12e 378 index = _settings.Session.Rx2DatarateIndex;
Jason Reiss 13:996f1663d12e 379 }
Jason Reiss 13:996f1663d12e 380 }
Jason Reiss 13:996f1663d12e 381
Jason Reiss 13:996f1663d12e 382 rxw.DatarateIndex = index;
Jason Reiss 13:996f1663d12e 383
Jason Reiss 13:996f1663d12e 384 return rxw;
Jason Reiss 13:996f1663d12e 385 }
Jason Reiss 13:996f1663d12e 386
Jason Reiss 13:996f1663d12e 387 uint8_t CustomChannelPlan_AS923::HandleRxParamSetup(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
Jason Reiss 13:996f1663d12e 388 status = 0x07;
Jason Reiss 13:996f1663d12e 389 int8_t datarate = 0;
Jason Reiss 13:996f1663d12e 390 int8_t drOffset = 0;
Jason Reiss 13:996f1663d12e 391 uint32_t freq = 0;
Jason Reiss 13:996f1663d12e 392
Jason Reiss 13:996f1663d12e 393 drOffset = payload[index++];
Jason Reiss 13:996f1663d12e 394 datarate = drOffset & 0x0F;
Jason Reiss 13:996f1663d12e 395 drOffset = (drOffset >> 4) & 0x07;
Jason Reiss 13:996f1663d12e 396
Jason Reiss 13:996f1663d12e 397 freq = payload[index++];
Jason Reiss 13:996f1663d12e 398 freq |= payload[index++] << 8;
Jason Reiss 13:996f1663d12e 399 freq |= payload[index++] << 16;
Jason Reiss 13:996f1663d12e 400 freq *= 100;
Jason Reiss 13:996f1663d12e 401
Jason Reiss 13:996f1663d12e 402 if (!CheckRfFrequency(freq)) {
Jason Reiss 13:996f1663d12e 403 logInfo("Freq KO");
Jason Reiss 13:996f1663d12e 404 status &= 0xFE; // Channel frequency KO
Jason Reiss 13:996f1663d12e 405 }
Jason Reiss 13:996f1663d12e 406
Jason Reiss 13:996f1663d12e 407 if (datarate < _minRx2Datarate || datarate > _maxRx2Datarate) {
Jason Reiss 13:996f1663d12e 408 logInfo("DR KO");
Jason Reiss 13:996f1663d12e 409 status &= 0xFD; // Datarate KO
Jason Reiss 13:996f1663d12e 410 }
Jason Reiss 13:996f1663d12e 411
Jason Reiss 13:996f1663d12e 412 if (drOffset < 0 || drOffset > _maxDatarateOffset) {
Jason Reiss 13:996f1663d12e 413 logInfo("DR Offset KO");
Jason Reiss 13:996f1663d12e 414 status &= 0xFB; // Rx1DrOffset range KO
Jason Reiss 13:996f1663d12e 415 }
Jason Reiss 13:996f1663d12e 416
Jason Reiss 13:996f1663d12e 417 if ((status & 0x07) == 0x07) {
Jason Reiss 13:996f1663d12e 418 logInfo("RxParamSetup accepted Rx2DR: %d Rx2Freq: %d Rx1Offset: %d", datarate, freq, drOffset);
Jason Reiss 13:996f1663d12e 419 SetRx2DatarateIndex(datarate);
Jason Reiss 13:996f1663d12e 420 SetRx2Frequency(freq);
Jason Reiss 13:996f1663d12e 421 SetRx1Offset(drOffset);
Jason Reiss 13:996f1663d12e 422 } else {
Jason Reiss 13:996f1663d12e 423 logInfo("RxParamSetup rejected Rx2DR: %d Rx2Freq: %d Rx1Offset: %d", datarate, freq, drOffset);
Jason Reiss 13:996f1663d12e 424 }
Jason Reiss 13:996f1663d12e 425
Jason Reiss 13:996f1663d12e 426 return LORA_OK;
Jason Reiss 13:996f1663d12e 427 }
Jason Reiss 13:996f1663d12e 428
Jason Reiss 13:996f1663d12e 429 uint8_t CustomChannelPlan_AS923::HandleNewChannel(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
Jason Reiss 13:996f1663d12e 430
Jason Reiss 13:996f1663d12e 431 status = 0x03;
Jason Reiss 13:996f1663d12e 432 uint8_t channelIndex = 0;
Jason Reiss 13:996f1663d12e 433 Channel chParam;
Jason Reiss 13:996f1663d12e 434
Jason Reiss 13:996f1663d12e 435 channelIndex = payload[index++];
Jason Reiss 13:996f1663d12e 436 lora::CopyFreqtoInt(payload + index, chParam.Frequency);
Jason Reiss 13:996f1663d12e 437 index += 3;
Jason Reiss 13:996f1663d12e 438 chParam.DrRange.Value = payload[index++];
Jason Reiss 13:996f1663d12e 439
Jason Reiss 13:996f1663d12e 440 if (channelIndex < 2 || channelIndex > _channels.size() - 1) {
Jason Reiss 13:996f1663d12e 441 logError("New Channel index KO");
Jason Reiss 13:996f1663d12e 442 status &= 0xFE; // Channel index KO
Jason Reiss 13:996f1663d12e 443 }
Jason Reiss 13:996f1663d12e 444
Jason Reiss 13:996f1663d12e 445 if (!_radio.CheckRfFrequency(chParam.Frequency)) {
Jason Reiss 13:996f1663d12e 446 logError("New Channel frequency KO");
Jason Reiss 13:996f1663d12e 447 status &= 0xFE; // Channel frequency KO
Jason Reiss 13:996f1663d12e 448 }
Jason Reiss 13:996f1663d12e 449
Jason Reiss 13:996f1663d12e 450 if (chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max) {
Jason Reiss 13:996f1663d12e 451 logError("New Channel datarate min/max KO");
Jason Reiss 13:996f1663d12e 452 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 453 } else if (chParam.DrRange.Fields.Min < _minDatarate || chParam.DrRange.Fields.Min > _maxDatarate) {
Jason Reiss 13:996f1663d12e 454 logError("New Channel datarate min KO");
Jason Reiss 13:996f1663d12e 455 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 456 } else if (chParam.DrRange.Fields.Max < _minDatarate || chParam.DrRange.Fields.Max > _maxDatarate) {
Jason Reiss 13:996f1663d12e 457 logError("New Channel datarate max KO");
Jason Reiss 13:996f1663d12e 458 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 459 }
Jason Reiss 13:996f1663d12e 460
Jason Reiss 13:996f1663d12e 461 if ((status & 0x03) == 0x03) {
Jason Reiss 13:996f1663d12e 462 logInfo("New Channel accepted index: %d freq: %lu drRange: %02x", channelIndex, chParam.Frequency, chParam.DrRange.Value);
Jason Reiss 13:996f1663d12e 463 AddChannel(channelIndex, chParam);
Jason Reiss 13:996f1663d12e 464 SetChannelMask(0, _channelMask[0] | 1 << (channelIndex));
Jason Reiss 13:996f1663d12e 465 }
Jason Reiss 13:996f1663d12e 466
Jason Reiss 13:996f1663d12e 467 return LORA_OK;
Jason Reiss 13:996f1663d12e 468 }
Jason Reiss 13:996f1663d12e 469
Jason Reiss 13:996f1663d12e 470 uint8_t CustomChannelPlan_AS923::HandlePingSlotChannelReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
Jason Reiss 13:996f1663d12e 471
Jason Reiss 13:996f1663d12e 472 lora::CopyFreqtoInt(payload + index, _beaconRxChannel.Frequency);
Jason Reiss 13:996f1663d12e 473 index += 3;
Jason Reiss 13:996f1663d12e 474
Jason Reiss 13:996f1663d12e 475 if (_beaconRxChannel.Frequency != 0) {
Jason Reiss 13:996f1663d12e 476 _beaconRxChannel.DrRange.Value = payload[index];
Jason Reiss 13:996f1663d12e 477 } else {
Jason Reiss 13:996f1663d12e 478 // TODO: set to default beacon rx channel
Jason Reiss 13:996f1663d12e 479 }
Jason Reiss 13:996f1663d12e 480
Jason Reiss 13:996f1663d12e 481 status = 0x03;
Jason Reiss 13:996f1663d12e 482 return LORA_OK;
Jason Reiss 13:996f1663d12e 483 }
Jason Reiss 13:996f1663d12e 484
Jason Reiss 13:996f1663d12e 485 uint8_t CustomChannelPlan_AS923::HandleBeaconFrequencyReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
Jason Reiss 13:996f1663d12e 486
Jason Reiss 13:996f1663d12e 487 status = 0x03;
Jason Reiss 13:996f1663d12e 488 Channel chParam;
Jason Reiss 13:996f1663d12e 489
Jason Reiss 13:996f1663d12e 490 // Skip channel index
Jason Reiss 13:996f1663d12e 491 index++;
Jason Reiss 13:996f1663d12e 492
Jason Reiss 13:996f1663d12e 493 lora::CopyFreqtoInt(payload + index, chParam.Frequency);
Jason Reiss 13:996f1663d12e 494 index += 3;
Jason Reiss 13:996f1663d12e 495 chParam.DrRange.Value = payload[index++];
Jason Reiss 13:996f1663d12e 496
Jason Reiss 13:996f1663d12e 497 if (!_radio.CheckRfFrequency(chParam.Frequency)) {
Jason Reiss 13:996f1663d12e 498 status &= 0xFE; // Channel frequency KO
Jason Reiss 13:996f1663d12e 499 }
Jason Reiss 13:996f1663d12e 500
Jason Reiss 13:996f1663d12e 501 if (chParam.DrRange.Fields.Min < chParam.DrRange.Fields.Max) {
Jason Reiss 13:996f1663d12e 502 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 503 } else if (chParam.DrRange.Fields.Min < _minDatarate || chParam.DrRange.Fields.Min > _maxDatarate) {
Jason Reiss 13:996f1663d12e 504 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 505 } else if (chParam.DrRange.Fields.Max < _minDatarate || chParam.DrRange.Fields.Max > _maxDatarate) {
Jason Reiss 13:996f1663d12e 506 status &= 0xFD; // Datarate range KO
Jason Reiss 13:996f1663d12e 507 }
Jason Reiss 13:996f1663d12e 508
Jason Reiss 13:996f1663d12e 509 if ((status & 0x03) == 0x03) {
Jason Reiss 13:996f1663d12e 510 _beaconChannel = chParam;
Jason Reiss 13:996f1663d12e 511 }
Jason Reiss 13:996f1663d12e 512
Jason Reiss 13:996f1663d12e 513 if (_beaconChannel.Frequency == 0) {
Jason Reiss 13:996f1663d12e 514 // TODO: Set to default
Jason Reiss 13:996f1663d12e 515 }
Jason Reiss 13:996f1663d12e 516
Jason Reiss 13:996f1663d12e 517 status = 0x01;
Jason Reiss 13:996f1663d12e 518
Jason Reiss 13:996f1663d12e 519 return LORA_OK;
Jason Reiss 13:996f1663d12e 520 }
Jason Reiss 13:996f1663d12e 521
Jason Reiss 13:996f1663d12e 522 bool CustomChannelPlan_AS923::AdrAckReq() {
Jason Reiss 13:996f1663d12e 523 if (_settings.Network.ADREnabled == false)
Jason Reiss 13:996f1663d12e 524 return false;
Jason Reiss 13:996f1663d12e 525
Jason Reiss 13:996f1663d12e 526 bool ret = false;
Jason Reiss 13:996f1663d12e 527
Jason Reiss 13:996f1663d12e 528 if (_settings.Session.TxDatarate == MIN_DATARATE) {
Jason Reiss 13:996f1663d12e 529 _settings.Session.AdrCounter = 0;
Jason Reiss 13:996f1663d12e 530 } else {
Jason Reiss 13:996f1663d12e 531 logDebug("ADR ACK CNT: %d LIMIT: %d DELAY: %d", _settings.Session.AdrCounter, ADR_ACK_LIMIT, ADR_ACK_DELAY);
Jason Reiss 13:996f1663d12e 532
Jason Reiss 13:996f1663d12e 533 ret = (_settings.Session.AdrCounter >= ADR_ACK_LIMIT);
Jason Reiss 13:996f1663d12e 534
Jason Reiss 13:996f1663d12e 535 if (_settings.Session.AdrCounter >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) {
Jason Reiss 13:996f1663d12e 536 if (_settings.Session.AdrCounter - 1 % ADR_ACK_DELAY == 0) {
Jason Reiss 13:996f1663d12e 537
Jason Reiss 13:996f1663d12e 538 if (_settings.Session.TxDatarate > MIN_DATARATE) {
Jason Reiss 13:996f1663d12e 539 _settings.Session.TxDatarate--;
Jason Reiss 13:996f1663d12e 540 }
Jason Reiss 13:996f1663d12e 541
Jason Reiss 13:996f1663d12e 542 if (_settings.Session.TxDatarate == MIN_DATARATE) {
Jason Reiss 13:996f1663d12e 543 EnableDefaultChannels();
Jason Reiss 13:996f1663d12e 544 }
Jason Reiss 13:996f1663d12e 545 }
Jason Reiss 13:996f1663d12e 546 }
Jason Reiss 13:996f1663d12e 547
Jason Reiss 13:996f1663d12e 548 }
Jason Reiss 13:996f1663d12e 549
Jason Reiss 13:996f1663d12e 550 return ret;
Jason Reiss 13:996f1663d12e 551 }
Jason Reiss 13:996f1663d12e 552
Jason Reiss 13:996f1663d12e 553 uint8_t CustomChannelPlan_AS923::HandleAdrCommand(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
Jason Reiss 13:996f1663d12e 554
Jason Reiss 13:996f1663d12e 555 uint8_t power = 0;
Jason Reiss 13:996f1663d12e 556 uint8_t datarate = 0;
Jason Reiss 13:996f1663d12e 557 uint16_t mask = 0;
Jason Reiss 13:996f1663d12e 558 uint8_t ctrl = 0;
Jason Reiss 13:996f1663d12e 559 uint8_t nbRep = 0;
Jason Reiss 13:996f1663d12e 560
Jason Reiss 13:996f1663d12e 561 status = 0x07;
Jason Reiss 13:996f1663d12e 562 datarate = payload[index++];
Jason Reiss 13:996f1663d12e 563 power = datarate & 0x0F;
Jason Reiss 13:996f1663d12e 564 datarate = (datarate >> 4) & 0x0F;
Jason Reiss 13:996f1663d12e 565
Jason Reiss 13:996f1663d12e 566 mask = payload[index++];
Jason Reiss 13:996f1663d12e 567 mask |= payload[index++] << 8;
Jason Reiss 13:996f1663d12e 568
Jason Reiss 13:996f1663d12e 569 nbRep = payload[index++];
Jason Reiss 13:996f1663d12e 570 ctrl = (nbRep >> 4) & 0x07;
Jason Reiss 13:996f1663d12e 571 nbRep &= 0x0F;
Jason Reiss 13:996f1663d12e 572
Jason Reiss 13:996f1663d12e 573 if (nbRep == 0) {
Jason Reiss 13:996f1663d12e 574 nbRep = 1;
Jason Reiss 13:996f1663d12e 575 }
Jason Reiss 13:996f1663d12e 576
Jason Reiss 13:996f1663d12e 577 if (!(mask == 0 && ctrl == 0)) {
Jason Reiss 13:996f1663d12e 578 if (ctrl == 5) {
Jason Reiss 13:996f1663d12e 579 mask = 0;
Jason Reiss 13:996f1663d12e 580 ctrl = 0;
Jason Reiss 13:996f1663d12e 581 }
Jason Reiss 13:996f1663d12e 582 }
Jason Reiss 13:996f1663d12e 583
Jason Reiss 13:996f1663d12e 584 if (datarate > _maxDatarate) {
Jason Reiss 13:996f1663d12e 585 logDebug("ADR Datarate KO");
Jason Reiss 13:996f1663d12e 586 status &= 0xFD; // Datarate KO
Jason Reiss 13:996f1663d12e 587 }
Jason Reiss 13:996f1663d12e 588 //
Jason Reiss 13:996f1663d12e 589 // Remark MaxTxPower = 0 and MinTxPower = 5
Jason Reiss 13:996f1663d12e 590 //
Jason Reiss 13:996f1663d12e 591 if (power > 5) {
Jason Reiss 13:996f1663d12e 592 logDebug("ADR TxPower KO");
Jason Reiss 13:996f1663d12e 593 status &= 0xFB; // TxPower KO
Jason Reiss 13:996f1663d12e 594 }
Jason Reiss 13:996f1663d12e 595
Jason Reiss 13:996f1663d12e 596 if ((status & 0x07) == 0x07) {
Jason Reiss 13:996f1663d12e 597 logDebug("ADR settings accepted");
Jason Reiss 13:996f1663d12e 598
Jason Reiss 13:996f1663d12e 599 if (_settings.Network.ADREnabled) {
Jason Reiss 13:996f1663d12e 600 _settings.Session.TxDatarate = datarate;
Jason Reiss 13:996f1663d12e 601 _settings.Session.TxPower = _settings.Session.Max_EIRP - (power * 2);
Jason Reiss 13:996f1663d12e 602 } else {
Jason Reiss 13:996f1663d12e 603 logInfo("ADR is disabled, DR and Power not changed.");
Jason Reiss 13:996f1663d12e 604 status &= 0xFB; // TxPower KO
Jason Reiss 13:996f1663d12e 605 status &= 0xFD; // Datarate KO
Jason Reiss 13:996f1663d12e 606 }
Jason Reiss 13:996f1663d12e 607
Jason Reiss 13:996f1663d12e 608 if (!(mask == 0 && ctrl == 0) || ((mask >= 1 && ctrl <= 5) || ctrl == 7)) {
Jason Reiss 13:996f1663d12e 609 for (uint8_t i = 0; i < _numChans125k; i++) {
Jason Reiss 13:996f1663d12e 610 if (ctrl == 6) {
Jason Reiss 13:996f1663d12e 611 // enable all defined channels
Jason Reiss 13:996f1663d12e 612 if (_channels[i].Frequency != 0) {
Jason Reiss 13:996f1663d12e 613 mask |= 1 << i;
Jason Reiss 13:996f1663d12e 614 }
Jason Reiss 13:996f1663d12e 615 } else {
Jason Reiss 13:996f1663d12e 616 if (((mask & (1 << i)) != 0) && (_channels[i].Frequency == 0)) {
Jason Reiss 13:996f1663d12e 617 // Trying to enable an undefined channel
Jason Reiss 13:996f1663d12e 618 status &= 0xFE; // Channel mask KO
Jason Reiss 13:996f1663d12e 619 }
Jason Reiss 13:996f1663d12e 620 }
Jason Reiss 13:996f1663d12e 621 }
Jason Reiss 13:996f1663d12e 622 SetChannelMask(0, mask);
Jason Reiss 13:996f1663d12e 623 } else {
Jason Reiss 13:996f1663d12e 624 if (mask == 0 && ctrl == 0) {
Jason Reiss 13:996f1663d12e 625 logWarning("Rejecting ADR command to disable all channels");
Jason Reiss 13:996f1663d12e 626 }
Jason Reiss 13:996f1663d12e 627 status &= 0xFE;
Jason Reiss 13:996f1663d12e 628 }
Jason Reiss 13:996f1663d12e 629 _settings.Session.Redundancy = nbRep;
Jason Reiss 13:996f1663d12e 630 }
Jason Reiss 13:996f1663d12e 631
Jason Reiss 13:996f1663d12e 632
Jason Reiss 13:996f1663d12e 633 logDebug("ADR DR: %u PWR: %u Ctrl: %02x Mask: %04x NbRep: %u Stat: %02x", datarate, power, ctrl, mask, nbRep, status);
Jason Reiss 13:996f1663d12e 634
Jason Reiss 13:996f1663d12e 635 return LORA_OK;
Jason Reiss 13:996f1663d12e 636 }
Jason Reiss 13:996f1663d12e 637
Jason Reiss 13:996f1663d12e 638 uint8_t CustomChannelPlan_AS923::HandleAckTimeout() {
Jason Reiss 13:996f1663d12e 639
Jason Reiss 13:996f1663d12e 640 if (!_settings.Network.ADREnabled) {
Jason Reiss 13:996f1663d12e 641 return LORA_ADR_OFF;
Jason Reiss 13:996f1663d12e 642 }
Jason Reiss 13:996f1663d12e 643
Jason Reiss 13:996f1663d12e 644 if ((++_settings.Session.AckCounter % 2) == 0) {
Jason Reiss 13:996f1663d12e 645 if (_settings.Session.TxPower < _settings.Network.TxPowerMax) {
Jason Reiss 13:996f1663d12e 646 logTrace("ADR Setting power to maximum");
Jason Reiss 13:996f1663d12e 647 _settings.Session.TxPower = _settings.Network.TxPowerMax;
Jason Reiss 13:996f1663d12e 648 } else if (_settings.Session.TxDatarate > 0) {
Jason Reiss 13:996f1663d12e 649 logTrace("ADR Lowering datarate");
Jason Reiss 13:996f1663d12e 650 _settings.Session.TxDatarate--;
Jason Reiss 13:996f1663d12e 651 }
Jason Reiss 13:996f1663d12e 652 }
Jason Reiss 13:996f1663d12e 653
Jason Reiss 13:996f1663d12e 654 return LORA_OK;
Jason Reiss 13:996f1663d12e 655 }
Jason Reiss 13:996f1663d12e 656
Jason Reiss 13:996f1663d12e 657
Jason Reiss 13:996f1663d12e 658 uint32_t CustomChannelPlan_AS923::GetTimeOffAir()
Jason Reiss 13:996f1663d12e 659 {
Jason Reiss 13:996f1663d12e 660 if (_settings.Test.DisableDutyCycle == lora::ON)
Jason Reiss 13:996f1663d12e 661 return 0;
Jason Reiss 13:996f1663d12e 662
Jason Reiss 13:996f1663d12e 663 uint32_t min = 0;
Jason Reiss 13:996f1663d12e 664 uint32_t now = _dutyCycleTimer.read_ms();
Jason Reiss 13:996f1663d12e 665
Jason Reiss 13:996f1663d12e 666
Jason Reiss 13:996f1663d12e 667 min = UINT_MAX;
Jason Reiss 13:996f1663d12e 668 int8_t band = 0;
Jason Reiss 13:996f1663d12e 669
Jason Reiss 13:996f1663d12e 670 if (P2PEnabled()) {
Jason Reiss 13:996f1663d12e 671 int8_t band = GetDutyBand(_settings.Network.TxFrequency);
Jason Reiss 13:996f1663d12e 672 if (_dutyBands[band].TimeOffEnd > now) {
Jason Reiss 13:996f1663d12e 673 min = _dutyBands[band].TimeOffEnd - now;
Jason Reiss 13:996f1663d12e 674 } else {
Jason Reiss 13:996f1663d12e 675 min = 0;
Jason Reiss 13:996f1663d12e 676 }
Jason Reiss 13:996f1663d12e 677 } else {
Jason Reiss 13:996f1663d12e 678 for (size_t i = 0; i < _channels.size(); i++) {
Jason Reiss 13:996f1663d12e 679 if (IsChannelEnabled(i) && GetChannel(i).Frequency != 0 &&
Jason Reiss 13:996f1663d12e 680 !(_settings.Session.TxDatarate < GetChannel(i).DrRange.Fields.Min ||
Jason Reiss 13:996f1663d12e 681 _settings.Session.TxDatarate > GetChannel(i).DrRange.Fields.Max)) {
Jason Reiss 13:996f1663d12e 682
Jason Reiss 13:996f1663d12e 683 band = GetDutyBand(GetChannel(i).Frequency);
Jason Reiss 13:996f1663d12e 684 if (band != -1) {
Jason Reiss 13:996f1663d12e 685 // logDebug("band: %d time-off: %d now: %d", band, _dutyBands[band].TimeOffEnd, now);
Jason Reiss 13:996f1663d12e 686 if (_dutyBands[band].TimeOffEnd > now) {
Jason Reiss 13:996f1663d12e 687 min = std::min < uint32_t > (min, _dutyBands[band].TimeOffEnd - now);
Jason Reiss 13:996f1663d12e 688 } else {
Jason Reiss 13:996f1663d12e 689 min = 0;
Jason Reiss 13:996f1663d12e 690 break;
Jason Reiss 13:996f1663d12e 691 }
Jason Reiss 13:996f1663d12e 692 }
Jason Reiss 13:996f1663d12e 693 }
Jason Reiss 13:996f1663d12e 694 }
Jason Reiss 13:996f1663d12e 695 }
Jason Reiss 13:996f1663d12e 696
Jason Reiss 13:996f1663d12e 697
Jason Reiss 13:996f1663d12e 698 if (_settings.Session.AggregatedTimeOffEnd > 0 && _settings.Session.AggregatedTimeOffEnd > now) {
Jason Reiss 13:996f1663d12e 699 min = std::max < uint32_t > (min, _settings.Session.AggregatedTimeOffEnd - now);
Jason Reiss 13:996f1663d12e 700 }
Jason Reiss 13:996f1663d12e 701
Jason Reiss 13:996f1663d12e 702 now = time(NULL);
Jason Reiss 13:996f1663d12e 703 uint32_t join_time = 0;
Jason Reiss 13:996f1663d12e 704
Jason Reiss 13:996f1663d12e 705 if (_settings.Session.JoinFirstAttempt != 0 && now < _settings.Session.JoinTimeOffEnd) {
Jason Reiss 13:996f1663d12e 706 join_time = (_settings.Session.JoinTimeOffEnd - now) * 1000;
Jason Reiss 13:996f1663d12e 707 }
Jason Reiss 13:996f1663d12e 708
Jason Reiss 13:996f1663d12e 709 min = std::max < uint32_t > (join_time, min);
Jason Reiss 13:996f1663d12e 710
Jason Reiss 13:996f1663d12e 711 return min;
Jason Reiss 13:996f1663d12e 712 }
Jason Reiss 13:996f1663d12e 713
Jason Reiss 13:996f1663d12e 714
Jason Reiss 13:996f1663d12e 715 void CustomChannelPlan_AS923::UpdateDutyCycle(uint32_t freq, uint32_t time_on_air_ms) {
Jason Reiss 13:996f1663d12e 716 if (_settings.Test.DisableDutyCycle == lora::ON) {
Jason Reiss 13:996f1663d12e 717 _dutyCycleTimer.stop();
Jason Reiss 13:996f1663d12e 718 for (size_t i = 0; i < _dutyBands.size(); i++) {
Jason Reiss 13:996f1663d12e 719 _dutyBands[i].TimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 720 }
Jason Reiss 13:996f1663d12e 721 return;
Jason Reiss 13:996f1663d12e 722 }
Jason Reiss 13:996f1663d12e 723
Jason Reiss 13:996f1663d12e 724 _dutyCycleTimer.start();
Jason Reiss 13:996f1663d12e 725
Jason Reiss 13:996f1663d12e 726 if (_settings.Session.MaxDutyCycle > 0 && _settings.Session.MaxDutyCycle <= 15) {
Jason Reiss 13:996f1663d12e 727 _settings.Session.AggregatedTimeOffEnd = _dutyCycleTimer.read_ms() + time_on_air_ms * _settings.Session.AggregateDutyCycle;
Jason Reiss 13:996f1663d12e 728 logDebug("Updated Aggregate DCycle Time-off: %lu DC: %f%%", _settings.Session.AggregatedTimeOffEnd, 1 / float(_settings.Session.AggregateDutyCycle));
Jason Reiss 13:996f1663d12e 729 } else {
Jason Reiss 13:996f1663d12e 730 _settings.Session.AggregatedTimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 731 }
Jason Reiss 13:996f1663d12e 732
Jason Reiss 13:996f1663d12e 733
Jason Reiss 13:996f1663d12e 734 uint32_t time_off_air = 0;
Jason Reiss 13:996f1663d12e 735 uint32_t now = _dutyCycleTimer.read_ms();
Jason Reiss 13:996f1663d12e 736
Jason Reiss 13:996f1663d12e 737 for (size_t i = 0; i < _dutyBands.size(); i++) {
Jason Reiss 13:996f1663d12e 738 if (_dutyBands[i].TimeOffEnd < now) {
Jason Reiss 13:996f1663d12e 739 _dutyBands[i].TimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 740 } else {
Jason Reiss 13:996f1663d12e 741 _dutyBands[i].TimeOffEnd -= now;
Jason Reiss 13:996f1663d12e 742 }
Jason Reiss 13:996f1663d12e 743
Jason Reiss 13:996f1663d12e 744 if (freq >= _dutyBands[i].FrequencyMin && freq <= _dutyBands[i].FrequencyMax) {
Jason Reiss 13:996f1663d12e 745 logDebug("update TOE: freq: %d i:%d toa: %d DC:%d", freq, i, time_on_air_ms, _dutyBands[i].DutyCycle);
Jason Reiss 13:996f1663d12e 746
Jason Reiss 13:996f1663d12e 747 if (freq > _minFrequency && freq < _maxFrequency && (_settings.Session.TxPower + _settings.Network.AntennaGain) <= 7) {
Jason Reiss 13:996f1663d12e 748 _dutyBands[i].TimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 749 } else {
Jason Reiss 13:996f1663d12e 750 time_off_air = time_on_air_ms * _dutyBands[i].DutyCycle;
Jason Reiss 13:996f1663d12e 751 _dutyBands[i].TimeOffEnd = time_off_air;
Jason Reiss 13:996f1663d12e 752 }
Jason Reiss 13:996f1663d12e 753 }
Jason Reiss 13:996f1663d12e 754 }
Jason Reiss 13:996f1663d12e 755
Jason Reiss 13:996f1663d12e 756
Jason Reiss 13:996f1663d12e 757 ResetDutyCycleTimer();
Jason Reiss 13:996f1663d12e 758 }
Jason Reiss 13:996f1663d12e 759
Jason Reiss 13:996f1663d12e 760 std::vector<uint32_t> lora::CustomChannelPlan_AS923::GetChannels() {
Jason Reiss 13:996f1663d12e 761 std::vector < uint32_t > chans;
Jason Reiss 13:996f1663d12e 762
Jason Reiss 13:996f1663d12e 763 for (int8_t i = 0; i < (int) _channels.size(); i++) {
Jason Reiss 13:996f1663d12e 764 chans.push_back(_channels[i].Frequency);
Jason Reiss 13:996f1663d12e 765 }
Jason Reiss 13:996f1663d12e 766 chans.push_back(GetRxWindow(2).Frequency);
Jason Reiss 13:996f1663d12e 767
Jason Reiss 13:996f1663d12e 768 return chans;
Jason Reiss 13:996f1663d12e 769 }
Jason Reiss 13:996f1663d12e 770
Jason Reiss 13:996f1663d12e 771 std::vector<uint8_t> lora::CustomChannelPlan_AS923::GetChannelRanges() {
Jason Reiss 13:996f1663d12e 772 std::vector < uint8_t > ranges;
Jason Reiss 13:996f1663d12e 773
Jason Reiss 13:996f1663d12e 774 for (int8_t i = 0; i < (int) _channels.size(); i++) {
Jason Reiss 13:996f1663d12e 775 ranges.push_back(_channels[i].DrRange.Value);
Jason Reiss 13:996f1663d12e 776 }
Jason Reiss 13:996f1663d12e 777
Jason Reiss 13:996f1663d12e 778 ranges.push_back(GetRxWindow(2).DatarateIndex);
Jason Reiss 13:996f1663d12e 779
Jason Reiss 13:996f1663d12e 780 return ranges;
Jason Reiss 13:996f1663d12e 781
Jason Reiss 13:996f1663d12e 782 }
Jason Reiss 13:996f1663d12e 783
Jason Reiss 13:996f1663d12e 784 void lora::CustomChannelPlan_AS923::EnableDefaultChannels() {
Jason Reiss 13:996f1663d12e 785 _channelMask[0] |= 0x0003;
Jason Reiss 13:996f1663d12e 786 }
Jason Reiss 13:996f1663d12e 787
Jason Reiss 13:996f1663d12e 788 uint8_t CustomChannelPlan_AS923::GetNextChannel()
Jason Reiss 13:996f1663d12e 789 {
Jason Reiss 13:996f1663d12e 790 if (_settings.Session.AggregatedTimeOffEnd != 0) {
Jason Reiss 13:996f1663d12e 791 return LORA_AGGREGATED_DUTY_CYCLE;
Jason Reiss 13:996f1663d12e 792 }
Jason Reiss 13:996f1663d12e 793
Jason Reiss 13:996f1663d12e 794 if (P2PEnabled() || _settings.Network.TxFrequency != 0) {
Jason Reiss 13:996f1663d12e 795 logDebug("Using frequency %d", _settings.Network.TxFrequency);
Jason Reiss 13:996f1663d12e 796
Jason Reiss 13:996f1663d12e 797 if (_settings.Test.DisableDutyCycle != lora::ON) {
Jason Reiss 13:996f1663d12e 798 int8_t band = GetDutyBand(_settings.Network.TxFrequency);
Jason Reiss 13:996f1663d12e 799 logDebug("band: %d freq: %d", band, _settings.Network.TxFrequency);
Jason Reiss 13:996f1663d12e 800 if (band != -1 && _dutyBands[band].TimeOffEnd != 0) {
Jason Reiss 13:996f1663d12e 801 return LORA_NO_CHANS_ENABLED;
Jason Reiss 13:996f1663d12e 802 }
Jason Reiss 13:996f1663d12e 803 }
Jason Reiss 13:996f1663d12e 804
Jason Reiss 13:996f1663d12e 805 _radio.SetChannel(_settings.Network.TxFrequency);
Jason Reiss 13:996f1663d12e 806 return LORA_OK;
Jason Reiss 13:996f1663d12e 807 }
Jason Reiss 13:996f1663d12e 808
Jason Reiss 13:996f1663d12e 809 uint8_t start = 0;
Jason Reiss 13:996f1663d12e 810 uint8_t maxChannels = _numChans125k;
Jason Reiss 13:996f1663d12e 811 uint8_t nbEnabledChannels = 0;
Jason Reiss 13:996f1663d12e 812 uint8_t *enabledChannels = new uint8_t[maxChannels];
Jason Reiss 13:996f1663d12e 813
Jason Reiss 13:996f1663d12e 814 if (GetTxDatarate().Bandwidth == BW_500) {
Jason Reiss 13:996f1663d12e 815 maxChannels = _numChans500k;
Jason Reiss 13:996f1663d12e 816 start = _numChans125k;
Jason Reiss 13:996f1663d12e 817 }
Jason Reiss 13:996f1663d12e 818
Jason Reiss 13:996f1663d12e 819 // Search how many channels are enabled
Jason Reiss 13:996f1663d12e 820 DatarateRange range;
Jason Reiss 13:996f1663d12e 821 uint8_t dr_index = _settings.Session.TxDatarate;
Jason Reiss 13:996f1663d12e 822 uint32_t now = _dutyCycleTimer.read_ms();
Jason Reiss 13:996f1663d12e 823
Jason Reiss 13:996f1663d12e 824 for (size_t i = 0; i < _dutyBands.size(); i++) {
Jason Reiss 13:996f1663d12e 825 if (_dutyBands[i].TimeOffEnd < now || _settings.Test.DisableDutyCycle == lora::ON) {
Jason Reiss 13:996f1663d12e 826 _dutyBands[i].TimeOffEnd = 0;
Jason Reiss 13:996f1663d12e 827 }
Jason Reiss 13:996f1663d12e 828 }
Jason Reiss 13:996f1663d12e 829
Jason Reiss 13:996f1663d12e 830 for (uint8_t i = start; i < start + maxChannels; i++) {
Jason Reiss 13:996f1663d12e 831 range = GetChannel(i).DrRange;
Jason Reiss 13:996f1663d12e 832 // logDebug("chan: %d freq: %d range:%02x", i, GetChannel(i).Frequency, range.Value);
Jason Reiss 13:996f1663d12e 833
Jason Reiss 13:996f1663d12e 834 if (IsChannelEnabled(i) && (dr_index >= range.Fields.Min && dr_index <= range.Fields.Max)) {
Jason Reiss 13:996f1663d12e 835 int8_t band = GetDutyBand(GetChannel(i).Frequency);
Jason Reiss 13:996f1663d12e 836 // logDebug("band: %d freq: %d", band, _channels[i].Frequency);
Jason Reiss 13:996f1663d12e 837 if (band != -1 && _dutyBands[band].TimeOffEnd == 0) {
Jason Reiss 13:996f1663d12e 838 enabledChannels[nbEnabledChannels++] = i;
Jason Reiss 13:996f1663d12e 839 }
Jason Reiss 13:996f1663d12e 840 }
Jason Reiss 13:996f1663d12e 841 }
Jason Reiss 13:996f1663d12e 842
Jason Reiss 13:996f1663d12e 843 logTrace("Number of available channels: %d", nbEnabledChannels);
Jason Reiss 13:996f1663d12e 844
Jason Reiss 13:996f1663d12e 845 uint32_t freq = 0;
Jason Reiss 13:996f1663d12e 846 uint8_t sf = GetTxDatarate().SpreadingFactor;
Jason Reiss 13:996f1663d12e 847 uint8_t bw = GetTxDatarate().Bandwidth;
Jason Reiss 13:996f1663d12e 848 int16_t thres = DEFAULT_FREE_CHAN_RSSI_THRESHOLD;
Jason Reiss 13:996f1663d12e 849
Jason Reiss 13:996f1663d12e 850 if (nbEnabledChannels == 0) {
Jason Reiss 13:996f1663d12e 851 delete [] enabledChannels;
Jason Reiss 13:996f1663d12e 852 return LORA_NO_CHANS_ENABLED;
Jason Reiss 13:996f1663d12e 853 }
Jason Reiss 13:996f1663d12e 854
Jason Reiss 13:996f1663d12e 855 if (_settings.Network.CADEnabled) {
Jason Reiss 13:996f1663d12e 856 // Search for free channel with ms timeout
Jason Reiss 13:996f1663d12e 857 int16_t timeout = 10000;
Jason Reiss 13:996f1663d12e 858 Timer tmr;
Jason Reiss 13:996f1663d12e 859 tmr.start();
Jason Reiss 13:996f1663d12e 860
Jason Reiss 13:996f1663d12e 861 for (uint8_t j = rand_r(0, nbEnabledChannels - 1); tmr.read_ms() < timeout; j++) {
Jason Reiss 13:996f1663d12e 862 freq = GetChannel(enabledChannels[j]).Frequency;
Jason Reiss 13:996f1663d12e 863
Jason Reiss 13:996f1663d12e 864 // Listen before talk
Jason Reiss 13:996f1663d12e 865 if (_radio.IsChannelFree(SxRadio::MODEM_LORA, freq, sf, thres, bw)) {
Jason Reiss 13:996f1663d12e 866 _txChannel = enabledChannels[j];
Jason Reiss 13:996f1663d12e 867 break;
Jason Reiss 13:996f1663d12e 868 }
Jason Reiss 13:996f1663d12e 869 }
Jason Reiss 13:996f1663d12e 870 } else {
Jason Reiss 13:996f1663d12e 871 uint8_t j = rand_r(0, nbEnabledChannels - 1);
Jason Reiss 13:996f1663d12e 872 _txChannel = enabledChannels[j];
Jason Reiss 13:996f1663d12e 873 freq = GetChannel(_txChannel).Frequency;
Jason Reiss 13:996f1663d12e 874 }
Jason Reiss 13:996f1663d12e 875
Jason Reiss 13:996f1663d12e 876 assert(freq != 0);
Jason Reiss 13:996f1663d12e 877
Jason Reiss 13:996f1663d12e 878 logDebug("Using channel %d : %d", _txChannel, freq);
Jason Reiss 13:996f1663d12e 879 _radio.SetChannel(freq);
Jason Reiss 13:996f1663d12e 880
Jason Reiss 13:996f1663d12e 881 delete [] enabledChannels;
Jason Reiss 13:996f1663d12e 882 return LORA_OK;
Jason Reiss 13:996f1663d12e 883 }
Jason Reiss 13:996f1663d12e 884
Jason Reiss 13:996f1663d12e 885
Jason Reiss 13:996f1663d12e 886 uint8_t lora::CustomChannelPlan_AS923::GetJoinDatarate() {
Jason Reiss 13:996f1663d12e 887 uint8_t dr = _settings.Session.TxDatarate;
Jason Reiss 13:996f1663d12e 888
Jason Reiss 13:996f1663d12e 889 // Default join datarate is DR2:SF10BW125
Jason Reiss 13:996f1663d12e 890 dr = lora::DR_2;
Jason Reiss 13:996f1663d12e 891
Jason Reiss 13:996f1663d12e 892 return dr;
Jason Reiss 13:996f1663d12e 893 }
Jason Reiss 13:996f1663d12e 894
Jason Reiss 13:996f1663d12e 895 uint8_t CustomChannelPlan_AS923::CalculateJoinBackoff(uint8_t size) {
Jason Reiss 13:996f1663d12e 896
Jason Reiss 13:996f1663d12e 897 time_t now = time(NULL);
Jason Reiss 13:996f1663d12e 898 uint32_t time_on_max = 0;
Jason Reiss 13:996f1663d12e 899 static uint32_t time_off_max = 15;
Jason Reiss 13:996f1663d12e 900 uint32_t rand_time_off = 0;
Jason Reiss 13:996f1663d12e 901
Jason Reiss 13:996f1663d12e 902 // TODO: calc time-off-max based on RTC time from JoinFirstAttempt, time-off-max is lost over sleep
Jason Reiss 13:996f1663d12e 903
Jason Reiss 13:996f1663d12e 904 if ((time_t)_settings.Session.JoinTimeOffEnd > now) {
Jason Reiss 13:996f1663d12e 905 return LORA_JOIN_BACKOFF;
Jason Reiss 13:996f1663d12e 906 }
Jason Reiss 13:996f1663d12e 907
Jason Reiss 13:996f1663d12e 908 uint32_t secs_since_first_attempt = (now - _settings.Session.JoinFirstAttempt);
Jason Reiss 13:996f1663d12e 909 uint16_t hours_since_first_attempt = secs_since_first_attempt / (60 * 60);
Jason Reiss 13:996f1663d12e 910
Jason Reiss 13:996f1663d12e 911 static uint8_t join_cnt = 0;
Jason Reiss 13:996f1663d12e 912
Jason Reiss 13:996f1663d12e 913 join_cnt = (join_cnt+1) % 8;
Jason Reiss 13:996f1663d12e 914
Jason Reiss 13:996f1663d12e 915 if (_settings.Session.JoinFirstAttempt == 0) {
Jason Reiss 13:996f1663d12e 916 /* 1 % duty-cycle for first hour
Jason Reiss 13:996f1663d12e 917 * 0.1 % next 10 hours
Jason Reiss 13:996f1663d12e 918 * 0.01 % upto 24 hours */
Jason Reiss 13:996f1663d12e 919 _settings.Session.JoinFirstAttempt = now;
Jason Reiss 13:996f1663d12e 920 _settings.Session.JoinTimeOnAir += GetTimeOnAir(size);
Jason Reiss 13:996f1663d12e 921 _settings.Session.JoinTimeOffEnd = now + (GetTimeOnAir(size) / 10);
Jason Reiss 13:996f1663d12e 922 } else if (join_cnt == 0) {
Jason Reiss 13:996f1663d12e 923 if (hours_since_first_attempt < 1) {
Jason Reiss 13:996f1663d12e 924 time_on_max = 36000;
Jason Reiss 13:996f1663d12e 925 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1);
Jason Reiss 13:996f1663d12e 926 // time off max 1 hour
Jason Reiss 13:996f1663d12e 927 time_off_max = std::min < uint32_t > (time_off_max * 2, 60 * 60);
Jason Reiss 13:996f1663d12e 928
Jason Reiss 13:996f1663d12e 929 if (_settings.Session.JoinTimeOnAir < time_on_max) {
Jason Reiss 13:996f1663d12e 930 _settings.Session.JoinTimeOnAir += GetTimeOnAir(size);
Jason Reiss 13:996f1663d12e 931 _settings.Session.JoinTimeOffEnd = now + rand_time_off;
Jason Reiss 13:996f1663d12e 932 } else {
Jason Reiss 13:996f1663d12e 933 logWarning("Max time-on-air limit met for current join backoff period");
Jason Reiss 13:996f1663d12e 934 _settings.Session.JoinTimeOffEnd = _settings.Session.JoinFirstAttempt + 60 * 60;
Jason Reiss 13:996f1663d12e 935 }
Jason Reiss 13:996f1663d12e 936 } else if (hours_since_first_attempt < 11) {
Jason Reiss 13:996f1663d12e 937 if (_settings.Session.JoinTimeOnAir < 36000) {
Jason Reiss 13:996f1663d12e 938 _settings.Session.JoinTimeOnAir = 36000;
Jason Reiss 13:996f1663d12e 939 }
Jason Reiss 13:996f1663d12e 940 time_on_max = 72000;
Jason Reiss 13:996f1663d12e 941 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1);
Jason Reiss 13:996f1663d12e 942 // time off max 1 hour
Jason Reiss 13:996f1663d12e 943 time_off_max = std::min < uint32_t > (time_off_max * 2, 60 * 60);
Jason Reiss 13:996f1663d12e 944
Jason Reiss 13:996f1663d12e 945 if (_settings.Session.JoinTimeOnAir < time_on_max) {
Jason Reiss 13:996f1663d12e 946 _settings.Session.JoinTimeOnAir += GetTimeOnAir(size);
Jason Reiss 13:996f1663d12e 947 _settings.Session.JoinTimeOffEnd = now + rand_time_off;
Jason Reiss 13:996f1663d12e 948 } else {
Jason Reiss 13:996f1663d12e 949 logWarning("Max time-on-air limit met for current join backoff period");
Jason Reiss 13:996f1663d12e 950 _settings.Session.JoinTimeOffEnd = _settings.Session.JoinFirstAttempt + 11 * 60 * 60;
Jason Reiss 13:996f1663d12e 951 }
Jason Reiss 13:996f1663d12e 952 } else {
Jason Reiss 13:996f1663d12e 953 if (_settings.Session.JoinTimeOnAir < 72000) {
Jason Reiss 13:996f1663d12e 954 _settings.Session.JoinTimeOnAir = 72000;
Jason Reiss 13:996f1663d12e 955 }
Jason Reiss 13:996f1663d12e 956 uint32_t join_time = 2500;
Jason Reiss 13:996f1663d12e 957
Jason Reiss 13:996f1663d12e 958 time_on_max = 80700;
Jason Reiss 13:996f1663d12e 959 time_off_max = 1 * 60 * 60; // 1 hour
Jason Reiss 13:996f1663d12e 960 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1);
Jason Reiss 13:996f1663d12e 961
Jason Reiss 13:996f1663d12e 962 if (_settings.Session.JoinTimeOnAir < time_on_max - join_time) {
Jason Reiss 13:996f1663d12e 963 _settings.Session.JoinTimeOnAir += GetTimeOnAir(size);
Jason Reiss 13:996f1663d12e 964 _settings.Session.JoinTimeOffEnd = now + rand_time_off;
Jason Reiss 13:996f1663d12e 965 } else {
Jason Reiss 13:996f1663d12e 966 logWarning("Max time-on-air limit met for current join backoff period");
Jason Reiss 13:996f1663d12e 967 // Reset the join time on air and set end of restriction to the next 24 hour period
Jason Reiss 13:996f1663d12e 968 _settings.Session.JoinTimeOnAir = 72000;
Jason Reiss 13:996f1663d12e 969 uint16_t days = (now - _settings.Session.JoinFirstAttempt) / (24 * 60 * 60) + 1;
Jason Reiss 13:996f1663d12e 970 logWarning("days : %d", days);
Jason Reiss 13:996f1663d12e 971 _settings.Session.JoinTimeOffEnd = _settings.Session.JoinFirstAttempt + ((days * 24) + 11) * 60 * 60;
Jason Reiss 13:996f1663d12e 972 }
Jason Reiss 13:996f1663d12e 973 }
Jason Reiss 13:996f1663d12e 974
Jason Reiss 13:996f1663d12e 975 logWarning("JoinBackoff: %lu seconds Time On Air: %lu / %lu", _settings.Session.JoinTimeOffEnd - now, _settings.Session.JoinTimeOnAir, time_on_max);
Jason Reiss 13:996f1663d12e 976 } else {
Jason Reiss 13:996f1663d12e 977 _settings.Session.JoinTimeOnAir += GetTimeOnAir(size);
Jason Reiss 13:996f1663d12e 978 _settings.Session.JoinTimeOffEnd = now + (GetTimeOnAir(size) / 10);
Jason Reiss 13:996f1663d12e 979 }
Jason Reiss 13:996f1663d12e 980
Jason Reiss 13:996f1663d12e 981 return LORA_OK;
Jason Reiss 13:996f1663d12e 982 }
Jason Reiss 13:996f1663d12e 983
Jason Reiss 13:996f1663d12e 984
Jason Reiss 13:996f1663d12e 985 uint8_t CustomChannelPlan_AS923::HandleMacCommands(uint8_t* payload, uint8_t index, uint8_t end_index) {
Jason Reiss 13:996f1663d12e 986
Jason Reiss 13:996f1663d12e 987 uint8_t ret = LORA_OK;
Jason Reiss 13:996f1663d12e 988
Jason Reiss 13:996f1663d12e 989 logDebug("AS923 Handle Mac index: %d end: %d", index, end_index);
Jason Reiss 13:996f1663d12e 990
Jason Reiss 13:996f1663d12e 991 while (index < end_index) {
Jason Reiss 13:996f1663d12e 992 switch (payload[index++]) {
Jason Reiss 13:996f1663d12e 993 case SRV_MAC_TX_PARAM_SETUP_REQ: {
Jason Reiss 13:996f1663d12e 994 uint8_t eirp_dwell = payload[index++];
Jason Reiss 13:996f1663d12e 995
Jason Reiss 13:996f1663d12e 996 // zero out command for MAC layer to skip
Jason Reiss 13:996f1663d12e 997 payload[index-2] = 0;
Jason Reiss 13:996f1663d12e 998 payload[index-1] = 0;
Jason Reiss 13:996f1663d12e 999
Jason Reiss 13:996f1663d12e 1000 _settings.Session.DownlinkDwelltime = eirp_dwell >> 5 & 0x01;
Jason Reiss 13:996f1663d12e 1001 _settings.Session.UplinkDwelltime = eirp_dwell >> 4 & 0x01;
Jason Reiss 13:996f1663d12e 1002 _settings.Session.Max_EIRP = MAX_ERP_VALUES[(eirp_dwell & 0x0F)];
Jason Reiss 13:996f1663d12e 1003 logDebug("buffer index %d", _settings.Session.CommandBufferIndex);
Jason Reiss 13:996f1663d12e 1004 if (_settings.Session.CommandBufferIndex < COMMANDS_BUFFER_SIZE) {
Jason Reiss 13:996f1663d12e 1005 logDebug("Add tx param setup mac cmd to buffer");
Jason Reiss 13:996f1663d12e 1006 _settings.Session.CommandBuffer[_settings.Session.CommandBufferIndex++] = MOTE_MAC_TX_PARAM_SETUP_ANS;
Jason Reiss 13:996f1663d12e 1007 }
Jason Reiss 13:996f1663d12e 1008
Jason Reiss 13:996f1663d12e 1009 logDebug("TX PARAM DWELL UL: %d DL: %d Max EIRP: %d", _settings.Session.UplinkDwelltime, _settings.Session.DownlinkDwelltime, _settings.Session.Max_EIRP);
Jason Reiss 13:996f1663d12e 1010 }
Jason Reiss 13:996f1663d12e 1011 break;
Jason Reiss 13:996f1663d12e 1012 case SRV_MAC_DL_CHANNEL_REQ: {
Jason Reiss 13:996f1663d12e 1013 uint8_t status = 0x03;
Jason Reiss 13:996f1663d12e 1014 uint8_t channelIndex = 0;
Jason Reiss 13:996f1663d12e 1015 Channel chParam;
Jason Reiss 13:996f1663d12e 1016
Jason Reiss 13:996f1663d12e 1017 channelIndex = payload[index++];
Jason Reiss 13:996f1663d12e 1018 lora::CopyFreqtoInt(payload + index, chParam.Frequency);
Jason Reiss 13:996f1663d12e 1019 index += 3;
Jason Reiss 13:996f1663d12e 1020
Jason Reiss 13:996f1663d12e 1021 // zero out command for MAC layer to skip
Jason Reiss 13:996f1663d12e 1022 payload[index-4] = 0;
Jason Reiss 13:996f1663d12e 1023 payload[index-3] = 0;
Jason Reiss 13:996f1663d12e 1024 payload[index-2] = 0;
Jason Reiss 13:996f1663d12e 1025 payload[index-1] = 0;
Jason Reiss 13:996f1663d12e 1026
Jason Reiss 13:996f1663d12e 1027 chParam.Index = channelIndex;
Jason Reiss 13:996f1663d12e 1028 chParam.DrRange.Value = 0;
Jason Reiss 13:996f1663d12e 1029
Jason Reiss 13:996f1663d12e 1030 if (channelIndex > 15) {
Jason Reiss 13:996f1663d12e 1031 status = 0x00;
Jason Reiss 13:996f1663d12e 1032 } else if (_channels[channelIndex].Frequency == 0) {
Jason Reiss 13:996f1663d12e 1033 status &= 0x02;
Jason Reiss 13:996f1663d12e 1034 } else if (chParam.Frequency != 0 && (chParam.Frequency < _minFrequency || chParam.Frequency > _maxFrequency)) {
Jason Reiss 13:996f1663d12e 1035 status &= 0x01;
Jason Reiss 13:996f1663d12e 1036 }
Jason Reiss 13:996f1663d12e 1037
Jason Reiss 13:996f1663d12e 1038 if (status == 0x03 && _settings.Session.CommandBufferIndex+1 < COMMANDS_BUFFER_SIZE) {
Jason Reiss 13:996f1663d12e 1039 AddDownlinkChannel(channelIndex, chParam);
Jason Reiss 13:996f1663d12e 1040 }
Jason Reiss 13:996f1663d12e 1041
Jason Reiss 13:996f1663d12e 1042 _settings.Session.DlChannelReqAnswer = status;
Jason Reiss 13:996f1663d12e 1043
Jason Reiss 13:996f1663d12e 1044 logDebug("DL Channel: index: %d freq: %d status: %d", channelIndex, chParam.Frequency, status);
Jason Reiss 13:996f1663d12e 1045 }
Jason Reiss 13:996f1663d12e 1046 break;
Jason Reiss 13:996f1663d12e 1047 }
Jason Reiss 13:996f1663d12e 1048 }
Jason Reiss 13:996f1663d12e 1049
Jason Reiss 13:996f1663d12e 1050 return ret;
Jason Reiss 13:996f1663d12e 1051 }
Jason Reiss 13:996f1663d12e 1052