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

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