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