MultiTech / libxDot-dev-mbed5-deprecated

Dependents:   Dot-Examples Dot-AT-Firmware Dot-Examples TEST_FF1705 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ChannelPlan_US915.cpp Source File

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