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:
jreiss
Date:
Wed Jan 18 13:33:36 2017 +0000
Revision:
11:829f8c2ec1c3
Child:
12:2e8fda56093f
KR920: max DR 7; AS923: max tx power 36 max EIRP 20 defaults

Who changed what in which revision?

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