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_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
L-Tek FF1705