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