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