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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ChannelPlan_KR920.cpp Source File

ChannelPlan_KR920.cpp

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