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:
Thu Jan 26 13:07:53 2017 +0000
Revision:
12:2e8fda56093f
Parent:
11:829f8c2ec1c3
Child:
13:996f1663d12e
Adjust ADR DR step down packet by one; Initialize DL channel list with frequency:0 in AS923,EU868,IN865,KR920 plans

Who changed what in which revision?

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