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