Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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


L-Tek FF1705