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

ChannelPlan_AS923.cpp

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