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_EU868.cpp Source File

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