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_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


L-Tek FF1705