Bleeding edge development version of the xDot library for mbed 5. This version of the library is not guaranteed to be stable or well tested and should not be used in production or deployment scenarios.
Dependents: Dot-Examples Dot-AT-Firmware Dot-Examples TEST_FF1705 ... more
ChannelPlan_EU868.cpp
00001 /********************************************************************** 00002 * COPYRIGHT 2016 MULTI-TECH SYSTEMS, INC. 00003 * 00004 * ALL RIGHTS RESERVED BY AND FOR THE EXCLUSIVE BENEFIT OF 00005 * MULTI-TECH SYSTEMS, INC. 00006 * 00007 * MULTI-TECH SYSTEMS, INC. - CONFIDENTIAL AND PROPRIETARY 00008 * INFORMATION AND/OR TRADE SECRET. 00009 * 00010 * NOTICE: ALL CODE, PROGRAM, INFORMATION, SCRIPT, INSTRUCTION, 00011 * DATA, AND COMMENT HEREIN IS AND SHALL REMAIN THE CONFIDENTIAL 00012 * INFORMATION AND PROPERTY OF MULTI-TECH SYSTEMS, INC. 00013 * USE AND DISCLOSURE THEREOF, EXCEPT AS STRICTLY AUTHORIZED IN A 00014 * WRITTEN AGREEMENT SIGNED BY MULTI-TECH SYSTEMS, INC. IS PROHIBITED. 00015 * 00016 ***********************************************************************/ 00017 00018 #include "ChannelPlan_EU868.h" 00019 #include "limits.h" 00020 00021 using namespace lora; 00022 00023 // MWF - changed EU868_TX_POWERS to match final 1.0.2 regional spec 00024 const uint8_t ChannelPlan_EU868::EU868_TX_POWERS[] = { 16, 14, 12, 10, 8, 6, 4, 2 }; 00025 const uint8_t ChannelPlan_EU868::EU868_RADIO_POWERS[] = { 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20 }; 00026 const uint8_t ChannelPlan_EU868::EU868_MAX_PAYLOAD_SIZE[] = { 51, 51, 51, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0, 0 }; 00027 const uint8_t ChannelPlan_EU868::EU868_MAX_PAYLOAD_SIZE_REPEATER[] = { 51, 51, 51, 115, 222, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0 }; 00028 00029 ChannelPlan_EU868::ChannelPlan_EU868() 00030 : 00031 ChannelPlan(NULL, NULL) 00032 { 00033 00034 } 00035 00036 ChannelPlan_EU868::ChannelPlan_EU868(Settings* settings) 00037 : 00038 ChannelPlan(NULL, settings) 00039 { 00040 00041 } 00042 00043 ChannelPlan_EU868::ChannelPlan_EU868(SxRadio* radio, Settings* settings) 00044 : 00045 ChannelPlan(radio, settings) 00046 { 00047 00048 } 00049 00050 ChannelPlan_EU868::~ChannelPlan_EU868() { 00051 00052 } 00053 00054 void ChannelPlan_EU868::Init() { 00055 00056 _datarates.clear(); 00057 _channels.clear(); 00058 _dutyBands.clear(); 00059 00060 DutyBand band; 00061 00062 band.Index = 0; 00063 band.DutyCycle = 0; 00064 00065 Datarate dr; 00066 00067 _plan = EU868; 00068 _planName = "EU868"; 00069 _maxTxPower = 27; 00070 _minTxPower = 0; 00071 00072 _minFrequency = EU868_FREQ_MIN; 00073 _maxFrequency = EU868_FREQ_MAX; 00074 00075 TX_POWERS = EU868_TX_POWERS; 00076 RADIO_POWERS = EU868_RADIO_POWERS; 00077 MAX_PAYLOAD_SIZE = EU868_MAX_PAYLOAD_SIZE; 00078 MAX_PAYLOAD_SIZE_REPEATER = EU868_MAX_PAYLOAD_SIZE_REPEATER; 00079 00080 _minDatarate = EU868_MIN_DATARATE; 00081 _maxDatarate = EU868_MAX_DATARATE; 00082 00083 _minRx2Datarate = DR_0; 00084 _maxRx2Datarate = DR_7; 00085 00086 _minDatarateOffset = EU868_MIN_DATARATE_OFFSET; 00087 _maxDatarateOffset = EU868_MAX_DATARATE_OFFSET; 00088 00089 _numChans125k = EU868_125K_NUM_CHANS; 00090 _numChans500k = 0; 00091 00092 _numDefaultChans = EU868_DEFAULT_NUM_CHANS; 00093 00094 GetSettings()->Session.Rx2Frequency = EU868_RX2_FREQ; 00095 GetSettings()->Session.Rx2DatarateIndex = DR_0; 00096 00097 GetSettings()->Session.BeaconFrequency = EU868_BEACON_FREQ; 00098 GetSettings()->Session.BeaconFreqHop = false; 00099 GetSettings()->Session.PingSlotFrequency = EU868_BEACON_FREQ; 00100 GetSettings()->Session.PingSlotDatarateIndex = EU868_BEACON_DR; 00101 GetSettings()->Session.PingSlotFreqHop = false; 00102 00103 logInfo("Initialize datarates..."); 00104 00105 dr.SpreadingFactor = SF_12; 00106 00107 // Add DR0-5 00108 while (dr.SpreadingFactor >= SF_7) { 00109 AddDatarate(-1, dr); 00110 dr.SpreadingFactor--; 00111 dr.Index++; 00112 } 00113 00114 // Add DR6 00115 dr.SpreadingFactor = SF_7; 00116 dr.Bandwidth = BW_250; 00117 AddDatarate(-1, dr); 00118 dr.Index++; 00119 00120 // Add DR7 00121 dr.SpreadingFactor = SF_FSK; 00122 dr.Bandwidth = BW_FSK; 00123 dr.PreambleLength = 10; 00124 dr.Coderate = 0; 00125 AddDatarate(-1, dr); 00126 dr.Index++; 00127 00128 _maxDatarate = DR_7; 00129 00130 // Skip DR8-15 RFU 00131 dr.SpreadingFactor = SF_INVALID; 00132 while (dr.Index++ <= DR_15) { 00133 AddDatarate(-1, dr); 00134 } 00135 00136 GetSettings()->Session.TxDatarate = 0; 00137 00138 logInfo("Initialize channels..."); 00139 00140 Channel chan; 00141 chan.DrRange.Fields.Min = DR_0; 00142 chan.DrRange.Fields.Max = DR_5; 00143 chan.Index = 0; 00144 chan.Frequency = EU868_125K_FREQ_BASE; 00145 SetNumberOfChannels(EU868_125K_NUM_CHANS); 00146 00147 for (uint8_t i = 0; i < EU868_DEFAULT_NUM_CHANS; i++) { 00148 chan.DrRange.Fields.Max = DR_5; 00149 00150 AddChannel(i, chan); 00151 chan.Index++; 00152 chan.Frequency += EU868_125K_FREQ_STEP; 00153 } 00154 00155 chan.DrRange.Value = 0; 00156 chan.Frequency = 0; 00157 00158 for (uint8_t i = EU868_DEFAULT_NUM_CHANS; i < EU868_125K_NUM_CHANS; i++) { 00159 AddChannel(i, chan); 00160 chan.Index++; 00161 } 00162 00163 // Add downlink channel defaults 00164 chan.Index = 0; 00165 _dlChannels.resize(16); 00166 for (uint8_t i = 0; i < 16; i++) { 00167 AddDownlinkChannel(i, chan); 00168 chan.Index++; 00169 } 00170 00171 SetChannelMask(0, 0x07); 00172 00173 band.Index = 0; 00174 band.FrequencyMin = EU868_MILLI_FREQ_MIN; 00175 band.FrequencyMax = EU868_MILLI_FREQ_MAX; 00176 band.PowerMax = 14; 00177 band.TimeOffEnd = 0; 00178 00179 // Limiting to 865-868 allows for 1% duty cycle 00180 band.DutyCycle = 100; 00181 00182 AddDutyBand(-1, band); 00183 00184 band.Index++; 00185 band.FrequencyMin = EU868_CENTI_FREQ_MIN; 00186 band.FrequencyMax = EU868_CENTI_FREQ_MAX; 00187 band.DutyCycle = 100; 00188 00189 AddDutyBand(-1, band); 00190 00191 band.Index++; 00192 band.FrequencyMin = EU868_DECI_FREQ_MIN; 00193 band.FrequencyMax = EU868_DECI_FREQ_MAX; 00194 band.PowerMax = 27; 00195 band.DutyCycle = 10; 00196 00197 AddDutyBand(-1, band); 00198 00199 band.Index++; 00200 band.FrequencyMin = EU868_VAR_FREQ_MIN; 00201 band.FrequencyMax = EU868_VAR_FREQ_MAX; 00202 band.DutyCycle = 100; 00203 00204 AddDutyBand(-1, band); 00205 00206 band.Index++; 00207 band.FrequencyMin = EU868_MILLI_1_FREQ_MIN; 00208 band.FrequencyMax = EU868_MILLI_1_FREQ_MAX; 00209 band.PowerMax = 14; 00210 band.TimeOffEnd = 0; 00211 band.DutyCycle = 1000; 00212 00213 AddDutyBand(-1, band); 00214 00215 GetSettings()->Session.TxPower = GetSettings()->Network.TxPower; 00216 } 00217 00218 uint8_t ChannelPlan_EU868::AddChannel(int8_t index, Channel channel) { 00219 logTrace("Add Channel %d : %lu : %02x %d", index, channel.Frequency, channel.DrRange.Value, _channels.size()); 00220 00221 assert(index < (int) _channels.size()); 00222 00223 if (index >= 0) { 00224 _channels[index] = channel; 00225 } else { 00226 _channels.push_back(channel); 00227 } 00228 00229 return LORA_OK; 00230 } 00231 00232 uint8_t ChannelPlan_EU868::HandleJoinAccept(const uint8_t* buffer, uint8_t size) { 00233 00234 if (size == 33) { 00235 Channel ch; 00236 int index = 3; 00237 for (int i = 13; i < size - 5; i += 3) { 00238 00239 ch.Frequency = ((buffer[i]) | (buffer[i + 1] << 8) | (buffer[i + 2] << 16)) * 100u; 00240 00241 if (ch.Frequency > 0) { 00242 ch.Index = index; 00243 ch.DrRange.Fields.Min = static_cast<int8_t>(DR_0); 00244 ch.DrRange.Fields.Max = static_cast<int8_t>(DR_5); 00245 AddChannel(index, ch); 00246 00247 if (GetDutyBand(ch.Frequency) > -1) 00248 _channelMask[0] |= (1 << index); 00249 else 00250 _channelMask[0] |= ~(1 << index); 00251 00252 index += 1; 00253 } 00254 } 00255 } 00256 00257 return LORA_OK; 00258 } 00259 00260 uint8_t ChannelPlan_EU868::SetTxConfig() { 00261 00262 logInfo("Configure radio for TX"); 00263 00264 uint8_t band = GetDutyBand(GetChannel(_txChannel).Frequency); 00265 Datarate txDr = GetDatarate(GetSettings()->Session.TxDatarate); 00266 int8_t max_pwr = _dutyBands[band].PowerMax; 00267 00268 int8_t pwr = 0; 00269 00270 pwr = std::min < int8_t > (GetSettings()->Session.TxPower, max_pwr); 00271 pwr -= GetSettings()->Network.AntennaGain; 00272 00273 for (int i = 20; i >= 0; i--) { 00274 if (RADIO_POWERS[i] <= pwr) { 00275 pwr = i; 00276 break; 00277 } 00278 if (i == 0) { 00279 pwr = i; 00280 } 00281 } 00282 00283 logDebug("Session pwr: %d ant: %d max: %d", GetSettings()->Session.TxPower, GetSettings()->Network.AntennaGain, max_pwr); 00284 logDebug("Radio Power index: %d output: %d total: %d", pwr, RADIO_POWERS[pwr], RADIO_POWERS[pwr] + GetSettings()->Network.AntennaGain); 00285 00286 uint32_t bw = txDr.Bandwidth; 00287 uint32_t sf = txDr.SpreadingFactor; 00288 uint8_t cr = txDr.Coderate; 00289 uint8_t pl = txDr.PreambleLength; 00290 uint16_t fdev = 0; 00291 bool crc = txDr.Crc; 00292 bool iq = txDr.TxIQ; 00293 00294 if (GetSettings()->Network.DisableCRC == true) 00295 crc = false; 00296 00297 SxRadio::RadioModems_t modem = SxRadio::MODEM_LORA; 00298 00299 if (sf == SF_FSK) { 00300 modem = SxRadio::MODEM_FSK; 00301 sf = 50e3; 00302 fdev = 25e3; 00303 bw = 0; 00304 } 00305 00306 GetRadio()->SetTxConfig(modem, pwr, fdev, bw, sf, cr, pl, false, crc, false, 0, iq, 3e3); 00307 00308 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); 00309 00310 return LORA_OK; 00311 } 00312 00313 uint8_t ChannelPlan_EU868::SetRxConfig(uint8_t window, bool continuous, uint16_t wnd_growth) { 00314 00315 RxWindow rxw = GetRxWindow(window); 00316 00317 if (_dlChannels[_txChannel].Frequency != 0 && window == 1) 00318 GetRadio()->SetChannel(_dlChannels[_txChannel].Frequency); 00319 else 00320 GetRadio()->SetChannel(rxw.Frequency); 00321 00322 Datarate rxDr = GetDatarate(rxw.DatarateIndex); 00323 uint32_t bw = rxDr.Bandwidth; 00324 uint32_t sf = rxDr.SpreadingFactor; 00325 uint8_t cr = rxDr.Coderate; 00326 uint8_t pl = rxDr.PreambleLength; 00327 uint16_t sto = rxDr.SymbolTimeout() * wnd_growth; 00328 uint32_t afc = 0; 00329 bool fixLen = false; 00330 uint8_t payloadLen = 0U; 00331 bool crc = false; // downlink does not use CRC according to LORAWAN 00332 00333 if (GetSettings()->Network.DisableCRC == true) 00334 crc = false; 00335 00336 Datarate txDr = GetDatarate(GetSettings()->Session.TxDatarate); 00337 bool iq = txDr.RxIQ; 00338 00339 if (P2PEnabled()) { 00340 iq = txDr.TxIQ; 00341 } 00342 00343 // Beacon modifications - no I/Q inversion, fixed length rx, preamble 00344 if (window == RX_BEACON) { 00345 iq = txDr.TxIQ; 00346 fixLen = true; 00347 payloadLen = sizeof(BCNPayload); 00348 pl = BEACON_PREAMBLE_LENGTH; 00349 } 00350 00351 SxRadio::RadioModems_t modem = SxRadio::MODEM_LORA; 00352 00353 if (sf == SF_FSK) { 00354 modem = SxRadio::MODEM_FSK; 00355 sf = 50e3; 00356 cr = 0; 00357 bw = 0; 00358 afc = 83333; 00359 iq = false; 00360 crc = true; // FSK must use CRC 00361 } 00362 00363 // Disable printf's to actually receive packets, printing to debug may mess up the timing 00364 // logTrace("Configure radio for RX%d on freq: %lu", window, rxw.Frequency); 00365 // logTrace("RX SF: %u BW: %u CR: %u PL: %u STO: %u CRC: %d IQ: %d", sf, bw, cr, pl, sto, crc, iq); 00366 00367 GetRadio()->SetRxConfig(modem, bw, sf, cr, afc, pl, sto, fixLen, payloadLen, crc, false, 0, iq, continuous); 00368 00369 return LORA_OK; 00370 } 00371 00372 Channel ChannelPlan_EU868::GetChannel(int8_t index) { 00373 Channel chan; 00374 memset(&chan, 0, sizeof(Channel)); 00375 00376 chan = _channels[index]; 00377 00378 return chan; 00379 } 00380 00381 uint8_t ChannelPlan_EU868::SetFrequencySubBand(uint8_t sub_band) { 00382 return LORA_OK; 00383 } 00384 00385 void ChannelPlan_EU868::LogRxWindow(uint8_t wnd) { 00386 00387 RxWindow rxw = GetRxWindow(wnd); 00388 Datarate rxDr = GetDatarate(rxw.DatarateIndex); 00389 uint8_t bw = rxDr.Bandwidth; 00390 uint8_t sf = rxDr.SpreadingFactor; 00391 uint8_t cr = rxDr.Coderate; 00392 uint8_t pl = rxDr.PreambleLength; 00393 uint16_t sto = rxDr.SymbolTimeout(); 00394 bool crc = false; // downlink does not use CRC according to LORAWAN 00395 bool iq = GetTxDatarate().RxIQ; 00396 uint32_t freq = rxw.Frequency; 00397 00398 if (wnd == 1 && _dlChannels[_txChannel].Frequency != 0) 00399 freq = _dlChannels[_txChannel].Frequency; 00400 00401 logTrace("RX%d on freq: %lu", wnd, freq); 00402 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); 00403 } 00404 00405 RxWindow ChannelPlan_EU868::GetRxWindow(uint8_t window) { 00406 RxWindow rxw; 00407 int index = 0; 00408 00409 if (P2PEnabled()) { 00410 rxw.Frequency = GetSettings()->Network.TxFrequency; 00411 index = GetSettings()->Session.TxDatarate; 00412 } else { 00413 switch (window) { 00414 case RX_1: 00415 rxw.Frequency = _channels[_txChannel].Frequency; 00416 00417 if (GetSettings()->Session.TxDatarate > GetSettings()->Session.Rx1DatarateOffset) { 00418 index = GetSettings()->Session.TxDatarate - GetSettings()->Session.Rx1DatarateOffset; 00419 } else { 00420 index = 0; 00421 } 00422 00423 break; 00424 00425 case RX_BEACON: 00426 rxw.Frequency = GetSettings()->Session.BeaconFrequency; 00427 index = EU868_BEACON_DR; 00428 break; 00429 00430 case RX_SLOT: 00431 rxw.Frequency = GetSettings()->Session.PingSlotFrequency; 00432 index = GetSettings()->Session.PingSlotDatarateIndex; 00433 break; 00434 00435 // RX2, RXC, RX_TEST, etc.. 00436 default: 00437 rxw.Frequency = GetSettings()->Session.Rx2Frequency; 00438 index = GetSettings()->Session.Rx2DatarateIndex; 00439 } 00440 } 00441 00442 rxw.DatarateIndex = index; 00443 00444 return rxw; 00445 } 00446 00447 uint8_t ChannelPlan_EU868::HandleRxParamSetup(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) { 00448 status = 0x07; 00449 int8_t datarate = 0; 00450 int8_t drOffset = 0; 00451 uint32_t freq = 0; 00452 00453 drOffset = payload[index++]; 00454 datarate = drOffset & 0x0F; 00455 drOffset = (drOffset >> 4) & 0x07; 00456 00457 freq = payload[index++]; 00458 freq |= payload[index++] << 8; 00459 freq |= payload[index++] << 16; 00460 freq *= 100; 00461 00462 if (!CheckRfFrequency(freq)) { 00463 logInfo("Freq KO"); 00464 status &= 0xFE; // Channel frequency KO 00465 } 00466 00467 if (datarate < _minRx2Datarate || datarate > _maxRx2Datarate) { 00468 logInfo("DR KO"); 00469 status &= 0xFD; // Datarate KO 00470 } 00471 00472 if (drOffset < 0 || drOffset > _maxDatarateOffset) { 00473 logInfo("DR Offset KO"); 00474 status &= 0xFB; // Rx1DrOffset range KO 00475 } 00476 00477 if ((status & 0x07) == 0x07) { 00478 logInfo("RxParamSetup accepted Rx2DR: %d Rx2Freq: %d Rx1Offset: %d", datarate, freq, drOffset); 00479 SetRx2DatarateIndex(datarate); 00480 SetRx2Frequency(freq); 00481 SetRx1Offset(drOffset); 00482 } else { 00483 logInfo("RxParamSetup rejected Rx2DR: %d Rx2Freq: %d Rx1Offset: %d", datarate, freq, drOffset); 00484 } 00485 00486 return LORA_OK; 00487 } 00488 00489 uint8_t ChannelPlan_EU868::HandleNewChannel(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) { 00490 00491 status = 0x03; 00492 uint8_t channelIndex = 0; 00493 Channel chParam; 00494 00495 channelIndex = payload[index++]; 00496 lora::CopyFreqtoInt(payload + index, chParam.Frequency); 00497 index += 3; 00498 chParam.DrRange.Value = payload[index++]; 00499 00500 if (channelIndex < 3 || channelIndex > _channels.size() - 1) { 00501 logError("New Channel index KO"); 00502 status &= 0xFE; // Channel index KO 00503 } 00504 00505 if (chParam.Frequency == 0) { 00506 chParam.DrRange.Value = 0; 00507 } else if (chParam.Frequency < _minFrequency || chParam.Frequency > _maxFrequency) { 00508 logError("New Channel frequency KO"); 00509 status &= 0xFE; // Channel frequency KO 00510 } 00511 00512 if (chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max && chParam.Frequency != 0) { 00513 logError("New Channel datarate min/max KO"); 00514 status &= 0xFD; // Datarate range KO 00515 } else if ((chParam.DrRange.Fields.Min < _minDatarate || chParam.DrRange.Fields.Min > _maxDatarate) && 00516 chParam.Frequency != 0) { 00517 logError("New Channel datarate min KO"); 00518 status &= 0xFD; // Datarate range KO 00519 } else if ((chParam.DrRange.Fields.Max < _minDatarate || chParam.DrRange.Fields.Max > _maxDatarate) && 00520 chParam.Frequency != 0) { 00521 logError("New Channel datarate max KO"); 00522 status &= 0xFD; // Datarate range KO 00523 } 00524 00525 if ((status & 0x03) == 0x03) { 00526 logInfo("New Channel accepted index: %d freq: %lu drRange: %02x", channelIndex, chParam.Frequency, chParam.DrRange.Value); 00527 AddChannel(channelIndex, chParam); 00528 SetChannelMask(0, _channelMask[0] | 1 << (channelIndex)); 00529 } 00530 00531 return LORA_OK; 00532 } 00533 00534 uint8_t ChannelPlan_EU868::HandlePingSlotChannelReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) { 00535 uint8_t datarate = 0; 00536 uint32_t freq = 0; 00537 00538 status = 0x03; 00539 00540 freq = payload[index++]; 00541 freq |= payload[index++] << 8; 00542 freq |= payload[index++] << 16; 00543 freq *= 100; 00544 00545 datarate = payload[index] & 0x0F; 00546 00547 if (freq == 0U) { 00548 logInfo("Received request to reset ping slot frequency to default"); 00549 freq = EU868_BEACON_FREQ; 00550 } else if (!CheckRfFrequency(freq)) { 00551 logInfo("Freq KO"); 00552 status &= 0xFE; // Channel frequency KO 00553 } 00554 00555 if (datarate < _minRx2Datarate || datarate > _maxRx2Datarate) { 00556 logInfo("DR KO"); 00557 status &= 0xFD; // Datarate KO 00558 } 00559 00560 if ((status & 0x03) == 0x03) { 00561 logInfo("PingSlotChannelReq accepted DR: %d Freq: %d", datarate, freq); 00562 GetSettings()->Session.PingSlotFrequency = freq; 00563 GetSettings()->Session.PingSlotDatarateIndex = datarate; 00564 } else { 00565 logInfo("PingSlotChannelReq rejected DR: %d Freq: %d", datarate, freq); 00566 } 00567 00568 return LORA_OK; 00569 } 00570 00571 uint8_t ChannelPlan_EU868::HandleBeaconFrequencyReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) 00572 { 00573 uint32_t freq = 0; 00574 00575 status = 0x01; 00576 00577 freq = payload[index++]; 00578 freq |= payload[index++] << 8; 00579 freq |= payload[index] << 16; 00580 freq *= 100; 00581 00582 if (freq == 0U) { 00583 logInfo("Received request to reset beacon frequency to default"); 00584 freq = EU868_BEACON_FREQ; 00585 } else if (!CheckRfFrequency(freq)) { 00586 logInfo("Freq KO"); 00587 status &= 0xFE; // Channel frequency KO 00588 } 00589 00590 if (status & 0x01) { 00591 logInfo("BeaconFrequencyReq accepted Freq: %d", freq); 00592 GetSettings()->Session.BeaconFrequency = freq; 00593 } else { 00594 logInfo("BeaconFrequencyReq rejected Freq: %d", freq); 00595 } 00596 00597 return LORA_OK; 00598 } 00599 00600 uint8_t ChannelPlan_EU868::HandleAdrCommand(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) { 00601 00602 uint8_t power = 0; 00603 uint8_t datarate = 0; 00604 uint16_t mask = 0; 00605 uint16_t new_mask = 0; 00606 uint8_t ctrl = 0; 00607 uint8_t nbRep = 0; 00608 00609 status = 0x07; 00610 datarate = payload[index++]; 00611 power = datarate & 0x0F; 00612 datarate = (datarate >> 4) & 0x0F; 00613 00614 mask = payload[index++]; 00615 mask |= payload[index++] << 8; 00616 00617 nbRep = payload[index++]; 00618 ctrl = (nbRep >> 4) & 0x07; 00619 nbRep &= 0x0F; 00620 00621 if (nbRep == 0) { 00622 nbRep = 1; 00623 } 00624 00625 if (datarate > _maxDatarate) { 00626 status &= 0xFD; // Datarate KO 00627 } 00628 // 00629 // Remark MaxTxPower = 0 and MinTxPower = 7 00630 // 00631 if (power > 7) { 00632 status &= 0xFB; // TxPower KO 00633 } 00634 00635 switch (ctrl) { 00636 case 0: 00637 SetChannelMask(0, mask); 00638 break; 00639 00640 case 6: 00641 // enable all currently defined channels 00642 // set bits 0 - N of a number by (2<<N)-1 00643 new_mask = (1 << _channels.size()) - 1; 00644 SetChannelMask(0, new_mask); 00645 break; 00646 00647 default: 00648 logWarning("rejecting RFU or unknown control value %d", ctrl); 00649 status &= 0xFE; // ChannelMask KO 00650 return LORA_ERROR; 00651 } 00652 00653 if (GetSettings()->Network.ADREnabled) { 00654 if (status == 0x07) { 00655 GetSettings()->Session.TxDatarate = datarate; 00656 GetSettings()->Session.TxPower = TX_POWERS[power]; 00657 GetSettings()->Session.Redundancy = nbRep; 00658 } 00659 } else { 00660 logDebug("ADR is disabled, DR and Power not changed."); 00661 status &= 0xFB; // TxPower KO 00662 status &= 0xFD; // Datarate KO 00663 } 00664 00665 logDebug("ADR DR: %u PWR: %u Ctrl: %02x Mask: %04x NbRep: %u Stat: %02x", datarate, power, ctrl, mask, nbRep, status); 00666 00667 return LORA_OK; 00668 } 00669 00670 uint8_t ChannelPlan_EU868::ValidateAdrConfiguration() { 00671 uint8_t status = 0x07; 00672 uint8_t datarate = GetSettings()->Session.TxDatarate; 00673 uint8_t power = GetSettings()->Session.TxPower; 00674 00675 if (!GetSettings()->Network.ADREnabled) { 00676 logDebug("ADR disabled - no applied changes to validate"); 00677 return status; 00678 } 00679 00680 if (datarate > _maxDatarate) { 00681 logWarning("ADR Datarate KO - outside allowed range"); 00682 status &= 0xFD; // Datarate KO 00683 } 00684 if (power < _minTxPower || power > _maxTxPower) { 00685 logWarning("ADR TX Power KO - outside allowed range"); 00686 status &= 0xFB; // TxPower KO 00687 } 00688 00689 // mask must not contain any undefined channels 00690 for (int i = 3; i < 16; i++) { 00691 if ((_channelMask[0] & (1 << i)) && (_channels[i].Frequency == 0)) { 00692 logWarning("ADR Channel Mask KO - cannot enable undefined channel"); 00693 status &= 0xFE; // ChannelMask KO 00694 break; 00695 } 00696 } 00697 00698 return status; 00699 } 00700 00701 uint8_t ChannelPlan_EU868::HandleAckTimeout() { 00702 00703 if (!GetSettings()->Network.ADREnabled) { 00704 return LORA_ADR_OFF; 00705 } 00706 00707 if ((++(GetSettings()->Session.AckCounter) % 2) == 0) { 00708 if (GetSettings()->Session.TxPower < GetSettings()->Network.TxPowerMax) { 00709 logTrace("ADR Setting power to maximum"); 00710 GetSettings()->Session.TxPower = GetSettings()->Network.TxPowerMax; 00711 } else if (GetSettings()->Session.TxDatarate > 0) { 00712 logTrace("ADR Lowering datarate"); 00713 (GetSettings()->Session.TxDatarate)--; 00714 } 00715 } 00716 00717 return LORA_OK; 00718 } 00719 00720 00721 uint32_t ChannelPlan_EU868::GetTimeOffAir() 00722 { 00723 if (GetSettings()->Test.DisableDutyCycle == lora::ON) 00724 return 0; 00725 00726 uint32_t min = 0; 00727 uint32_t now = _dutyCycleTimer.read_ms(); 00728 00729 00730 min = UINT_MAX; 00731 int8_t band = 0; 00732 00733 if (P2PEnabled()) { 00734 int8_t band = GetDutyBand(GetSettings()->Network.TxFrequency); 00735 if (_dutyBands[band].TimeOffEnd > now) { 00736 min = _dutyBands[band].TimeOffEnd - now; 00737 } else { 00738 min = 0; 00739 } 00740 } else { 00741 for (size_t i = 0; i < _channels.size(); i++) { 00742 if (IsChannelEnabled(i) && GetChannel(i).Frequency != 0 && 00743 !(GetSettings()->Session.TxDatarate < GetChannel(i).DrRange.Fields.Min || 00744 GetSettings()->Session.TxDatarate > GetChannel(i).DrRange.Fields.Max)) { 00745 00746 band = GetDutyBand(GetChannel(i).Frequency); 00747 if (band != -1) { 00748 // logDebug("band: %d time-off: %d now: %d", band, _dutyBands[band].TimeOffEnd, now); 00749 if (_dutyBands[band].TimeOffEnd > now) { 00750 min = std::min < uint32_t > (min, _dutyBands[band].TimeOffEnd - now); 00751 } else { 00752 min = 0; 00753 break; 00754 } 00755 } 00756 } 00757 } 00758 } 00759 00760 00761 if (GetSettings()->Session.AggregatedTimeOffEnd > 0 && GetSettings()->Session.AggregatedTimeOffEnd > now) { 00762 min = std::max < uint32_t > (min, GetSettings()->Session.AggregatedTimeOffEnd - now); 00763 } 00764 00765 now = time(NULL); 00766 uint32_t join_time = 0; 00767 00768 if (GetSettings()->Session.JoinFirstAttempt != 0 && now < GetSettings()->Session.JoinTimeOffEnd) { 00769 join_time = (GetSettings()->Session.JoinTimeOffEnd - now) * 1000; 00770 } 00771 00772 min = std::max < uint32_t > (join_time, min); 00773 00774 return min; 00775 } 00776 00777 00778 void ChannelPlan_EU868::UpdateDutyCycle(uint32_t freq, uint32_t time_on_air_ms) { 00779 if (GetSettings()->Test.DisableDutyCycle == lora::ON) { 00780 _dutyCycleTimer.stop(); 00781 for (size_t i = 0; i < _dutyBands.size(); i++) { 00782 _dutyBands[i].TimeOffEnd = 0; 00783 } 00784 return; 00785 } 00786 00787 _dutyCycleTimer.start(); 00788 00789 if (GetSettings()->Session.MaxDutyCycle > 0 && GetSettings()->Session.MaxDutyCycle <= 15) { 00790 GetSettings()->Session.AggregatedTimeOffEnd = _dutyCycleTimer.read_ms() + time_on_air_ms * GetSettings()->Session.AggregateDutyCycle; 00791 logDebug("Updated Aggregate DCycle Time-off: %lu DC: %f%%", GetSettings()->Session.AggregatedTimeOffEnd, 1 / float(GetSettings()->Session.AggregateDutyCycle)); 00792 } else { 00793 GetSettings()->Session.AggregatedTimeOffEnd = 0; 00794 } 00795 00796 00797 uint32_t time_off_air = 0; 00798 uint32_t now = _dutyCycleTimer.read_ms(); 00799 00800 for (size_t i = 0; i < _dutyBands.size(); i++) { 00801 if (_dutyBands[i].TimeOffEnd < now) { 00802 _dutyBands[i].TimeOffEnd = 0; 00803 } else { 00804 _dutyBands[i].TimeOffEnd -= now; 00805 } 00806 00807 if (freq >= _dutyBands[i].FrequencyMin && freq <= _dutyBands[i].FrequencyMax) { 00808 logDebug("update TOE: freq: %d i:%d toa: %d DC:%d", freq, i, time_on_air_ms, _dutyBands[i].DutyCycle); 00809 00810 if (freq > EU868_VAR_FREQ_MIN && freq < EU868_VAR_FREQ_MAX && (GetSettings()->Session.TxPower + GetSettings()->Network.AntennaGain) <= 7) { 00811 _dutyBands[i].TimeOffEnd = 0; 00812 } else { 00813 time_off_air = time_on_air_ms * _dutyBands[i].DutyCycle; 00814 _dutyBands[i].TimeOffEnd = time_off_air; 00815 } 00816 } 00817 } 00818 00819 00820 ResetDutyCycleTimer(); 00821 } 00822 00823 std::vector<uint32_t> lora::ChannelPlan_EU868::GetChannels() { 00824 std::vector < uint32_t > chans; 00825 00826 for (int8_t i = 0; i < (int) _channels.size(); i++) { 00827 chans.push_back(_channels[i].Frequency); 00828 } 00829 chans.push_back(GetRxWindow(2).Frequency); 00830 00831 return chans; 00832 } 00833 00834 std::vector<uint8_t> lora::ChannelPlan_EU868::GetChannelRanges() { 00835 std::vector < uint8_t > ranges; 00836 00837 for (int8_t i = 0; i < (int) _channels.size(); i++) { 00838 ranges.push_back(_channels[i].DrRange.Value); 00839 } 00840 00841 ranges.push_back(GetRxWindow(2).DatarateIndex); 00842 00843 return ranges; 00844 00845 } 00846 00847 void lora::ChannelPlan_EU868::EnableDefaultChannels() { 00848 _channelMask[0] |= 0x0007; 00849 } 00850 00851 uint8_t ChannelPlan_EU868::GetNextChannel() 00852 { 00853 if (GetSettings()->Session.AggregatedTimeOffEnd != 0) { 00854 return LORA_AGGREGATED_DUTY_CYCLE; 00855 } 00856 00857 if (P2PEnabled() || GetSettings()->Network.TxFrequency != 0) { 00858 logDebug("Using frequency %d", GetSettings()->Network.TxFrequency); 00859 00860 if (GetSettings()->Test.DisableDutyCycle != lora::ON) { 00861 int8_t band = GetDutyBand(GetSettings()->Network.TxFrequency); 00862 logDebug("band: %d freq: %d", band, GetSettings()->Network.TxFrequency); 00863 if (band != -1 && _dutyBands[band].TimeOffEnd != 0) { 00864 return LORA_NO_CHANS_ENABLED; 00865 } 00866 } 00867 00868 GetRadio()->SetChannel(GetSettings()->Network.TxFrequency); 00869 return LORA_OK; 00870 } 00871 00872 uint8_t start = 0; 00873 uint8_t maxChannels = _numChans125k; 00874 uint8_t nbEnabledChannels = 0; 00875 uint8_t *enabledChannels = new uint8_t[maxChannels]; 00876 00877 if (GetTxDatarate().Bandwidth == BW_500) { 00878 maxChannels = _numChans500k; 00879 start = _numChans125k; 00880 } 00881 00882 // Search how many channels are enabled 00883 DatarateRange range; 00884 uint8_t dr_index = GetSettings()->Session.TxDatarate; 00885 uint32_t now = _dutyCycleTimer.read_ms(); 00886 00887 for (size_t i = 0; i < _dutyBands.size(); i++) { 00888 if (_dutyBands[i].TimeOffEnd < now || GetSettings()->Test.DisableDutyCycle == lora::ON) { 00889 _dutyBands[i].TimeOffEnd = 0; 00890 } 00891 } 00892 00893 for (uint8_t i = start; i < start + maxChannels; i++) { 00894 range = GetChannel(i).DrRange; 00895 // logDebug("chan: %d freq: %d range:%02x", i, GetChannel(i).Frequency, range.Value); 00896 00897 if (IsChannelEnabled(i) && (dr_index >= range.Fields.Min && dr_index <= range.Fields.Max)) { 00898 int8_t band = GetDutyBand(GetChannel(i).Frequency); 00899 // logDebug("band: %d freq: %d", band, _channels[i].Frequency); 00900 if (band != -1 && _dutyBands[band].TimeOffEnd == 0) { 00901 enabledChannels[nbEnabledChannels++] = i; 00902 } 00903 } 00904 } 00905 00906 logTrace("Number of available channels: %d", nbEnabledChannels); 00907 00908 uint32_t freq = 0; 00909 uint8_t sf = GetTxDatarate().SpreadingFactor; 00910 uint8_t bw = GetTxDatarate().Bandwidth; 00911 int16_t thres = DEFAULT_FREE_CHAN_RSSI_THRESHOLD; 00912 00913 if (nbEnabledChannels == 0) { 00914 delete [] enabledChannels; 00915 return LORA_NO_CHANS_ENABLED; 00916 } 00917 00918 00919 if (GetSettings()->Network.CADEnabled) { 00920 // Search for free channel with ms timeout 00921 int16_t timeout = 10000; 00922 Timer tmr; 00923 tmr.start(); 00924 00925 for (uint8_t j = rand_r(0, nbEnabledChannels - 1); tmr.read_ms() < timeout; j++) { 00926 freq = GetChannel(enabledChannels[j]).Frequency; 00927 00928 if (GetRadio()->IsChannelFree(SxRadio::MODEM_LORA, freq, sf, thres, bw)) { 00929 _txChannel = enabledChannels[j]; 00930 break; 00931 } 00932 } 00933 } else { 00934 uint8_t j = rand_r(0, nbEnabledChannels - 1); 00935 _txChannel = enabledChannels[j]; 00936 freq = GetChannel(_txChannel).Frequency; 00937 } 00938 00939 assert(freq != 0); 00940 00941 logDebug("Using channel %d : %d", _txChannel, freq); 00942 GetRadio()->SetChannel(freq); 00943 00944 00945 delete [] enabledChannels; 00946 return LORA_OK; 00947 } 00948 00949 00950 uint8_t lora::ChannelPlan_EU868::GetJoinDatarate() { 00951 uint8_t dr = GetSettings()->Session.TxDatarate; 00952 static uint8_t cnt = 0; 00953 00954 if (GetSettings()->Test.DisableRandomJoinDatarate == lora::OFF) { 00955 if ((cnt++ % 20) == 0) { 00956 dr = lora::DR_0; 00957 } else if ((cnt % 16) == 0) { 00958 dr = lora::DR_1; 00959 } else if ((cnt % 12) == 0) { 00960 dr = lora::DR_2; 00961 } else if ((cnt % 8) == 0) { 00962 dr = lora::DR_3; 00963 } else if ((cnt % 4) == 0) { 00964 dr = lora::DR_4; 00965 } else { 00966 dr = lora::DR_5; 00967 } 00968 } 00969 00970 return dr; 00971 } 00972 00973 uint8_t ChannelPlan_EU868::CalculateJoinBackoff(uint8_t size) { 00974 00975 time_t now = time(NULL); 00976 uint32_t time_on_max = 0; 00977 static uint32_t time_off_max = 15; 00978 uint32_t rand_time_off = 0; 00979 00980 // TODO: calc time-off-max based on RTC time from JoinFirstAttempt, time-off-max is lost over sleep 00981 00982 if ((time_t)GetSettings()->Session.JoinTimeOffEnd > now) { 00983 return LORA_JOIN_BACKOFF; 00984 } 00985 00986 uint32_t secs_since_first_attempt = (now - GetSettings()->Session.JoinFirstAttempt); 00987 uint16_t hours_since_first_attempt = secs_since_first_attempt / (60 * 60); 00988 00989 static uint8_t join_cnt = 0; 00990 00991 join_cnt = (join_cnt+1) % 8; 00992 00993 if (GetSettings()->Session.JoinFirstAttempt == 0) { 00994 /* 1 % duty-cycle for first hour 00995 * 0.1 % next 10 hours 00996 * 0.01 % upto 24 hours */ 00997 GetSettings()->Session.JoinFirstAttempt = now; 00998 GetSettings()->Session.JoinTimeOnAir += GetTimeOnAir(size); 00999 GetSettings()->Session.JoinTimeOffEnd = now + (GetTimeOnAir(size) / 10); 01000 } else if (join_cnt == 0) { 01001 if (hours_since_first_attempt < 1) { 01002 time_on_max = 36000; 01003 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1); 01004 // time off max 1 hour 01005 time_off_max = std::min < uint32_t > (time_off_max * 2, 60 * 60); 01006 01007 if (GetSettings()->Session.JoinTimeOnAir < time_on_max) { 01008 GetSettings()->Session.JoinTimeOnAir += GetTimeOnAir(size); 01009 GetSettings()->Session.JoinTimeOffEnd = now + rand_time_off; 01010 } else { 01011 logWarning("Max time-on-air limit met for current join backoff period"); 01012 GetSettings()->Session.JoinTimeOffEnd = GetSettings()->Session.JoinFirstAttempt + 60 * 60; 01013 } 01014 } else if (hours_since_first_attempt < 11) { 01015 if (GetSettings()->Session.JoinTimeOnAir < 36000) { 01016 GetSettings()->Session.JoinTimeOnAir = 36000; 01017 } 01018 time_on_max = 72000; 01019 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1); 01020 // time off max 1 hour 01021 time_off_max = std::min < uint32_t > (time_off_max * 2, 60 * 60); 01022 01023 if (GetSettings()->Session.JoinTimeOnAir < time_on_max) { 01024 GetSettings()->Session.JoinTimeOnAir += GetTimeOnAir(size); 01025 GetSettings()->Session.JoinTimeOffEnd = now + rand_time_off; 01026 } else { 01027 logWarning("Max time-on-air limit met for current join backoff period"); 01028 GetSettings()->Session.JoinTimeOffEnd = GetSettings()->Session.JoinFirstAttempt + 11 * 60 * 60; 01029 } 01030 } else { 01031 if (GetSettings()->Session.JoinTimeOnAir < 72000) { 01032 GetSettings()->Session.JoinTimeOnAir = 72000; 01033 } 01034 uint32_t join_time = 1200; 01035 01036 time_on_max = 80700; 01037 time_off_max = 1 * 60 * 60; // 1 hour 01038 rand_time_off = rand_r(time_off_max - 1, time_off_max + 1); 01039 01040 // allow one final join attempt as long as it doesn't start past the max time on air 01041 if (GetSettings()->Session.JoinTimeOnAir < time_on_max - join_time) { 01042 GetSettings()->Session.JoinTimeOnAir += GetTimeOnAir(size); 01043 GetSettings()->Session.JoinTimeOffEnd = now + rand_time_off; 01044 } else { 01045 logWarning("Max time-on-air limit met for current join backoff period"); 01046 // Reset the join time on air and set end of restriction to the next 24 hour period 01047 GetSettings()->Session.JoinTimeOnAir = 72000; 01048 uint16_t days = (now - GetSettings()->Session.JoinFirstAttempt) / (24 * 60 * 60) + 1; 01049 logWarning("days : %d", days); 01050 GetSettings()->Session.JoinTimeOffEnd = GetSettings()->Session.JoinFirstAttempt + ((days * 24) + 11) * 60 * 60; 01051 } 01052 } 01053 01054 logWarning("JoinBackoff: %lu seconds Time On Air: %lu / %lu", GetSettings()->Session.JoinTimeOffEnd - now, GetSettings()->Session.JoinTimeOnAir, time_on_max); 01055 } else { 01056 GetSettings()->Session.JoinTimeOnAir += GetTimeOnAir(size); 01057 GetSettings()->Session.JoinTimeOffEnd = now + (GetTimeOnAir(size) / 10); 01058 } 01059 01060 return LORA_OK; 01061 } 01062 01063 bool ChannelPlan_EU868::DecodeBeacon(const uint8_t* payload, size_t size, BeaconData_t& data) { 01064 uint16_t crc1, crc1_rx, crc2, crc2_rx; 01065 const BCNPayload* beacon = (const BCNPayload*)payload; 01066 01067 // First check the size of the packet 01068 if (size != sizeof(BCNPayload)) 01069 return false; 01070 01071 // Next we verify the CRCs are correct 01072 crc1 = CRC16(beacon->RFU, sizeof(beacon->RFU) + sizeof(beacon->Time)); 01073 memcpy((uint8_t*)&crc1_rx, beacon->CRC1, sizeof(uint16_t)); 01074 01075 if (crc1 != crc1_rx) 01076 return false; 01077 01078 crc2 = CRC16(beacon->GwSpecific, sizeof(beacon->GwSpecific)); 01079 memcpy((uint8_t*)&crc2_rx, beacon->CRC2, sizeof(uint16_t)); 01080 01081 if (crc2 != crc2_rx) 01082 return false; 01083 01084 // Now that we have confirmed this packet is a beacon, parse and complete the output struct 01085 memcpy(&data.Time, beacon->Time, sizeof(beacon->Time)); 01086 data.InfoDesc = beacon->GwSpecific[0]; 01087 01088 // Update the GPS fields if we have a gps info descriptor 01089 if (data.InfoDesc == GPS_FIRST_ANTENNA || 01090 data.InfoDesc == GPS_SECOND_ANTENNA || 01091 data.InfoDesc == GPS_THIRD_ANTENNA) { 01092 // Latitude and Longitude 3 bytes in length 01093 memcpy(&data.Latitude, &beacon->GwSpecific[1], 3); 01094 memcpy(&data.Longitude, &beacon->GwSpecific[4], 3); 01095 } 01096 01097 return true; 01098 }
Generated on Tue Jul 12 2022 18:19:47 by 1.7.2