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