end node on synchronous star LoRa network.

Dependencies:   SX127x sx12xx_hal TSL2561

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaMacSingle.cpp Source File

LoRaMacSingle.cpp

00001 /* */
00002 
00003 #include <math.h>
00004 #include "board.h"
00005 #include "radio.h"
00006 
00007 #include "LoRaMacCrypto.h"
00008 #include "LoRaMacSingle.h"
00009 #include "LoRaMacTest.h"
00010 
00011 #define BEACONS_MISSED_LIMIT            16
00012 
00013 #define PING_SLOT_RESOLUTION_us         30000
00014 
00015 #define PREAMBLE_SYMBS                  8
00016 
00017 #define TARGET_PRECESSION_us            3000
00018 #define BEACON_RX_TIMEOUT_LOCKED_us     8000
00019 
00020 /*!
00021  * Maximum PHY layer payload size
00022  */
00023 #define LORAMAC_PHY_MAXPAYLOAD                      255
00024 
00025 /*!
00026  * Maximum MAC commands buffer size
00027  */
00028 #define LORA_MAC_COMMAND_MAX_LENGTH                 15
00029 
00030 LowPowerClock::time_point txDoneAt;
00031 
00032 /*!
00033  * Device IEEE EUI
00034  */
00035 static uint8_t *LoRaMacDevEui;
00036 
00037 /*!
00038  * Application IEEE EUI
00039  */
00040 static uint8_t *LoRaMacAppEui;
00041 
00042 /*!
00043  * AES encryption/decryption cipher application key
00044  */
00045 static uint8_t *LoRaMacAppKey;
00046 
00047 /*!
00048  * AES encryption/decryption cipher network session key
00049  */
00050 static uint8_t LoRaMacNwkSKey[] =
00051 {
00052     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00053     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00054 };
00055 
00056 /*!
00057  * AES encryption/decryption cipher application session key
00058  */
00059 static uint8_t LoRaMacAppSKey[] =
00060 {
00061     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00062     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00063 };
00064 
00065 /*!
00066  * Device nonce is a random value extracted by issuing a sequence of RSSI
00067  * measurements
00068  */
00069 static uint16_t LoRaMacDevNonce;
00070 
00071 /*!
00072  * Network ID ( 3 bytes )
00073  */
00074 static uint32_t LoRaMacNetID;
00075 
00076 /*!
00077  * Mote Address
00078  */
00079 static uint32_t LoRaMacDevAddr;
00080 
00081 /*!
00082  * Multicast channels linked list
00083  */
00084 static MulticastParams_t  *MulticastChannels = NULL;
00085 
00086 /*!
00087  * Indicates if the node is connected to a private or public network
00088  */
00089 static bool PublicNetwork;
00090 
00091 uint8_t tx_buf_len;
00092 
00093 static uint8_t rxFRMPayload[244];
00094 
00095 /*!
00096  * LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
00097  * Only the 16 LSB bits are sent
00098  */
00099 static uint32_t UpLinkCounter = 0;
00100 
00101 /*!
00102  * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
00103  * Only the 16 LSB bits are received
00104  */
00105 static uint32_t DownLinkCounter = 0;
00106 
00107 /*!
00108  * Used for test purposes. Disables the opening of the reception windows.
00109  */
00110 static bool IsRxWindowsEnabled = true;
00111 
00112 LowPowerTimeout rx_timeout;
00113 
00114 /* how long this MCU (we're running on) takes to wake-up from deep-sleep */
00115 microseconds mcu_wakeup_latency;
00116 
00117 LowPowerClock::time_point rx_timeout_setAt;
00118 
00119 /*!
00120  * Indicates if the MAC layer wants to send MAC commands
00121  */
00122 static bool MacCommandsInNextTx = false;
00123 
00124 /*!
00125  * Contains the current MacCommandsBuffer index
00126  */
00127 static uint8_t MacCommandsBufferIndex = 0;
00128 
00129 /*!
00130  * Contains the current MacCommandsBuffer index for MAC commands to repeat
00131  */
00132 static uint8_t MacCommandsBufferToRepeatIndex = 0;
00133 
00134 /*!
00135  * Buffer containing the MAC layer commands
00136  */
00137 static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
00138 
00139 /*!
00140  * Buffer containing the MAC layer commands which must be repeated
00141  */
00142 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
00143 
00144 #define BEACON_SIZE                 6   /* bytes */
00145 #define BEACON_CHANNEL_DR           LORAMAC_DEFAULT_DATARATE
00146 
00147 
00148 #ifdef SX128x_H 
00149     //                             0    1   2  3  4  5  6  7
00150     const uint8_t Datarates[]  = { 12, 11, 10, 9, 8, 7, 6, 5 };
00151     #define SF_FROM_DR0     12  /* DR0 is sf12 */
00152     #define SF_FROM_DR1     11  /* DR1 is sf11 */
00153     #define SF_FROM_DR2     10  /* DR2 is sf10 */
00154     #define SF_FROM_DR3      9  /* DR3 is sf9 */
00155     #define SF_FROM_DR4      8  /* DR4 is sf8 */
00156     #define SF_FROM_DR5      7  /* DR5 is sf7 */
00157     #define SF_FROM_DR6      6  /* DR5 is sf6 */
00158     #define SF_FROM_DR7      5  /* DR7 is sf5 */
00159 
00160 
00161     const int8_t TxPowers[] = { 12, 5 };
00162     #define LORAMAC_FIRST_CHANNEL           ( (uint32_t)2486.9e6 )
00163     #define LORAMAC_STEPWIDTH_CHANNEL       ( (uint32_t)300e3 )
00164     #define LORA_MAX_NB_CHANNELS            8
00165 
00166     #define LORA_BANDWIDTH_KHZ           200
00167 
00168     /* end sx1280 */
00169 #elif defined( USE_BAND_915_SINGLE )
00170     /*!
00171      * Data rates table definition
00172                     DR:             0  1  2   3   4   5   6  7   8  9   10  11 12 13 14 15*/
00173     const uint8_t Datarates[]  = { 10, 9, 8,  7,  8,  0,  0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
00174     #define SF_FROM_DR8        12
00175     #define SF_FROM_DR9        11
00176     #define SF_FROM_DR10       10
00177     #define SF_FROM_DR11        9
00178     #define SF_FROM_DR12        8
00179     #define SF_FROM_DR13        7
00180 
00181     /*!
00182      * Tx output powers table definition
00183      */
00184                                 // 0   1   2   3   4   5   6   7   8   9   10  11 12 13 14 15
00185     const int8_t TxPowers[]    = { 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 };
00186     #define LORAMAC_FIRST_CHANNEL           ( (uint32_t)910.0e6 )
00187     #define LORAMAC_STEPWIDTH_CHANNEL       ( (uint32_t)800e3 )
00188     #define LORA_MAX_NB_CHANNELS                        8
00189 
00190     #define LORA_BANDWIDTH_KHZ           500
00191 
00192     /* end us915 */
00193 #elif defined(USE_BAND_433)
00194                        //   DR:    0   1   2   3  4  5  6  7
00195     const uint8_t Datarates[]  = { 12, 11, 10, 9, 8, 7, 7, 50 };
00196     #define SF_FROM_DR0        12
00197     #define SF_FROM_DR1        11
00198     #define SF_FROM_DR2        10
00199     #define SF_FROM_DR3         9
00200     #define SF_FROM_DR4         8
00201     #define SF_FROM_DR5         7
00202 
00203     const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 };
00204     #define LORA_BANDWIDTH_KHZ           125
00205 
00206     #define LORAMAC_FIRST_CHANNEL           ( (uint32_t)433.32e6 )
00207     #define LORAMAC_STEPWIDTH_CHANNEL       ( (uint32_t)200e3 )
00208     #define LORA_MAX_NB_CHANNELS            7
00209 
00210     /* end USE_BAND_433 */
00211 #else
00212     #error "Please define a frequency band in the compiler options."
00213 #endif
00214 
00215 #define _SF_FROM_DR(dr)         SF_FROM_DR ## dr
00216 #define SF_FROM_DR_(x)          _SF_FROM_DR(x)
00217 
00218 #ifdef SX128x_H 
00219 
00220     #define FASTEST_SF      5
00221     /* ratio of symbol period to time from end of packet to RxDone interrupt */
00222 //  sp       200KHz                         160    320   640   1280  2560  5120  10240 20480
00223 // usLatency 200KHz implicit-6byte           90    228   436   880   2020  4200  8800  19300
00224                                     // SF:   5     6     7     8     9     10    11    12
00225     const float rxLatencyFactorFromSF[8] = { 0.56, 0.72, 0.68, 0.69, 0.79, 0.82, 0.86, 0.94 };
00226 
00227 #elif defined(SX126x_H) || defined(SX127x_H)
00228 
00229     #define FASTEST_SF      5
00230     /* ratio of symbol period to time from end of packet to RxDone interrupt */
00231 //  sp       500KHz                          64    128   256   512   1024  2048  4096  8192
00232 // usLatency 500KHz implicit-6byte                 92    184   376   780   1680  3680  7720
00233                                     // SF:   5     6     7     8     9     10    11    12
00234     const float rxLatencyFactorFromSF[8] = { 0.72, 0.72, 0.72, 0.73, 0.76, 0.82, 0.90, 0.94 };
00235 
00236 #endif /* SX126x_H || SX127x_H */
00237 
00238 static ChannelParams_t  Channels[LORA_MAX_NB_CHANNELS];  // populated in init
00239 
00240 #define BEACON_GUARD_us         2000000     // pre-beacon start
00241 #define BEACON_RESERVED_us      2120000     // post-beacon start
00242 
00243 #define MIN_SYMBOL_TIMEOUT       8   // number of symbols to keep receiver open for
00244 
00245 /*!
00246  * LoRaMac parameters
00247  */
00248 LoRaMacParams_t  LoRaMacParams;
00249 
00250 /*!
00251  * LoRaMac default parameters
00252  */
00253 LoRaMacParams_t  LoRaMacParamsDefaults;
00254 
00255 /*!
00256  * Uplink messages repetitions counter
00257  */
00258 static uint8_t ChannelsNbRepCounter = 0;
00259 
00260 /*!
00261  * Current channel index
00262  */
00263 static uint8_t Channel;
00264 
00265 /*!
00266  * LoRaMac upper layer event functions
00267  */
00268 static LoRaMacPrimitives_t  *LoRaMacPrimitives;
00269 
00270 /*!
00271  * LoRaMac upper layer callback functions
00272  */
00273 static LoRaMacCallback_t *LoRaMacCallbacks;
00274 
00275 /*!
00276  * LoRaMac duty cycle delayed Tx timer
00277  */
00278 LowPowerTimeout tx_timeout;
00279 
00280 /*!
00281  * LoRaMac reception windows delay
00282  * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
00283  *         join frame  : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
00284  */
00285 microseconds RxWindowDelay_us;
00286 
00287 typedef enum {
00288     BEACON_STATE_NONE = 0,
00289     BEACON_STATE_FIRST_ACQ,
00290     BEACON_STATE_ACQ_ERROR,
00291     BEACON_STATE_LOCKED,
00292 } beacon_state_e;
00293 
00294 static struct beacon_struct {
00295     int rx_precession_us; // positive: rxing before tx start, negative: rxing after tx start
00296     LowPowerClock::time_point rx_setup_at;
00297     LowPowerClock::time_point LastBeaconRxAt;   // was LastBeaconRx_us, updated only at beacon reception
00298     LowPowerClock::time_point sendAt;
00299     microseconds lastSendAtErr;
00300     int last_BeaconRxTimerError_us;
00301     int known_working_BeaconRxTimerError_us;
00302 
00303     unsigned symbol_period_us;
00304 
00305     uint8_t Precess_symbols;    // how many symbols we want to start receiver before expected transmitter
00306     uint16_t nSymbsTimeout;
00307     unsigned SymbolTimeout_us;
00308     uint8_t num_missed;
00309     uint8_t num_consecutive_ok;
00310 
00311     beacon_state_e state;
00312 
00313     uint16_t tx_slot_offset;
00314     uint16_t periodicity_slots;
00315     uint32_t beaconStartToRxDone;
00316     uint16_t sendOpportunities;
00317 
00318     LowPowerTimeout timeout_rx;
00319     LowPowerTimeout timeout_guard;
00320     bool guard;
00321 } BeaconCtx;
00322 
00323 /*!
00324  * Rx window parameters
00325  */
00326 typedef struct
00327 {
00328     int8_t Datarate;
00329     uint32_t RxWindowTimeout;
00330 } RxConfigParams_t;
00331 
00332 /*!
00333  * Rx windows params
00334  */
00335 static RxConfigParams_t RxWindowsParam;
00336 
00337 /*!
00338  * Acknowledge timeout timer. Used for packet retransmissions.
00339  */
00340 static LowPowerTimeout AckTimeoutTimer;
00341 
00342 /*!
00343  * Number of trials for the Join Request
00344  */
00345 static uint8_t JoinRequestTrials;
00346 
00347 /*!
00348  * Maximum number of trials for the Join Request
00349  */
00350 static uint8_t MaxJoinRequestTrials;
00351 
00352 /*!
00353  * Structure to hold an MCPS indication data.
00354  */
00355 static McpsIndication_t  McpsIndication;
00356 
00357 /*!
00358  * Structure to hold MCPS confirm data.
00359  */
00360 static McpsConfirm_t  McpsConfirm;
00361 
00362 /*!
00363  * Structure to hold MLME confirm data.
00364  */
00365 static MlmeConfirm_t  MlmeConfirm;
00366 
00367 /*!
00368  * Structure to hold MLME indication data.
00369  */
00370 static MlmeIndication_t MlmeIndication;
00371 
00372 /*!
00373  * LoRaMac tx/rx operation state
00374  */
00375 volatile LoRaMacFlags_t  LoRaMacFlags;
00376 
00377 /*!
00378  * \brief This function prepares the MAC to abort the execution of function
00379  *        OnRadioRxDone in case of a reception error.
00380  */
00381 static void PrepareRxDoneAbort( void );
00382 
00383 /*!
00384  * \brief Function executed on Radio Tx Timeout event
00385  */
00386 static void OnRadioTxTimeout( void );
00387 
00388 /*!
00389  * \brief Function executed on Radio Rx error event
00390  */
00391 static void OnRadioRxError( void );
00392 
00393 /*!
00394  * \brief Function executed on Radio Rx Timeout event
00395  */
00396 static void OnRadioRxTimeout( void );
00397 
00398 /*!
00399  * \brief Function executed on AckTimeout timer event
00400  */
00401 static void OnAckTimeoutTimerEvent( void );
00402 
00403 /*!
00404  * \brief Adds a new MAC command to be sent.
00405  *
00406  * \Remark MAC layer internal function
00407  *
00408  * \param [in] cmd MAC command to be added
00409  *                 [MOTE_MAC_LINK_CHECK_REQ,
00410  *                  MOTE_MAC_LINK_ADR_ANS,
00411  *                  MOTE_MAC_DUTY_CYCLE_ANS,
00412  *                  MOTE_MAC_RX2_PARAM_SET_ANS,
00413  *                  MOTE_MAC_DEV_STATUS_ANS
00414  *                  MOTE_MAC_NEW_CHANNEL_ANS]
00415  * \param [in] p1  1st parameter ( optional depends on the command )
00416  * \param [in] p2  2nd parameter ( optional depends on the command )
00417  *
00418  * \retval status  Function status [0: OK, 1: Unknown command, 2: Buffer full]
00419  */
00420 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 );
00421 
00422 /*!
00423  * \brief Parses the MAC commands which must be repeated.
00424  *
00425  * \Remark MAC layer internal function
00426  *
00427  * \param [IN] cmdBufIn  Buffer which stores the MAC commands to send
00428  * \param [IN] length  Length of the input buffer to parse
00429  * \param [OUT] cmdBufOut  Buffer which stores the MAC commands which must be
00430  *                         repeated.
00431  *
00432  * \retval Size of the MAC commands to repeat.
00433  */
00434 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut );
00435 
00436 /*!
00437  * \brief Verifies, if a value is in a given range.
00438  *
00439  * \param value Value to verify, if it is in range
00440  *
00441  * \param min Minimum possible value
00442  *
00443  * \param max Maximum possible value
00444  *
00445  * \retval Returns the maximum valid tx power
00446  */
00447 static bool ValueInRange( int8_t value, int8_t min, int8_t max );
00448 
00449 
00450 /*!
00451  * \brief Decodes MAC commands in the fOpts field and in the payload
00452  */
00453 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
00454 
00455 /*!
00456  * \brief LoRaMAC layer generic send frame
00457  *
00458  * \param [IN] macHdr      MAC header field
00459  * \param [IN] fPort       MAC payload port
00460  * \param [IN] fBuffer     MAC data buffer to be sent
00461  * \param [IN] fBufferSize MAC data buffer size
00462  * \retval status          Status of the operation.
00463  */
00464 LoRaMacStatus_t Send( LoRaMacHeader_t  *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
00465 
00466 /*!
00467  * \brief LoRaMAC layer frame buffer initialization
00468  *
00469  * \param [IN] macHdr      MAC header field
00470  * \param [IN] fCtrl       MAC frame control field
00471  * \param [IN] fOpts       MAC commands buffer
00472  * \param [IN] fPort       MAC payload port
00473  * \param [IN] fBuffer     MAC data buffer to be sent
00474  * \param [IN] fBufferSize MAC data buffer size
00475  * \retval status          Status of the operation.
00476  */
00477 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t  *macHdr, LoRaMacFrameCtrl_t  *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
00478 
00479 /*!
00480  * \brief Sets the radio in continuous transmission mode
00481  *
00482  * \remark Uses the radio parameters set on the previous transmission.
00483  *
00484  * \param [IN] timeout     Time in seconds while the radio is kept in continuous wave mode
00485  * \retval status          Status of the operation.
00486  */
00487 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout );
00488 
00489 /*!
00490  * \brief Sets the radio in continuous transmission mode
00491  *
00492  * \remark Uses the radio parameters set on the previous transmission.
00493  *
00494  * \param [IN] timeout     Time in seconds while the radio is kept in continuous wave mode
00495  * \param [IN] frequency   RF frequency to be set.
00496  * \param [IN] power       RF ouptput power to be set.
00497  * \retval status          Status of the operation.
00498  */
00499 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power );
00500 
00501 #ifdef SX127x_H
00502 void printLoraIrqs(bool clear)
00503 {
00504     pc_printf("\r\nIrqFlags:");
00505     if (Radio::lora.RegIrqFlags.bits.CadDetected)
00506         pc_printf("CadDetected ");
00507     if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) {
00508         pc_printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
00509     }
00510     if (Radio::lora.RegIrqFlags.bits.CadDone)
00511         pc_printf("CadDone ");
00512     if (Radio::lora.RegIrqFlags.bits.TxDone)
00513         pc_printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
00514     if (Radio::lora.RegIrqFlags.bits.ValidHeader)
00515         pc_printf("ValidHeader ");
00516     if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
00517         pc_printf("PayloadCrcError ");
00518     if (Radio::lora.RegIrqFlags.bits.RxDone)
00519         pc_printf("RxDone ");  
00520     if (Radio::lora.RegIrqFlags.bits.RxTimeout)
00521         pc_printf("RxTimeout ");
00522 
00523     pc_printf("\r\n");
00524 
00525     if (clear)
00526         Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet);
00527 }
00528 
00529 void printOpMode()
00530 {
00531     Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
00532     switch (Radio::radio.RegOpMode.bits.Mode) {
00533         case RF_OPMODE_SLEEP: pc_printf("sleep"); break;
00534         case RF_OPMODE_STANDBY: pc_printf("stby"); break;
00535         case RF_OPMODE_SYNTHESIZER_TX: pc_printf("fstx"); break;
00536         case RF_OPMODE_TRANSMITTER: pc_printf("tx"); break;
00537         case RF_OPMODE_SYNTHESIZER_RX: pc_printf("fsrx"); break;
00538         case RF_OPMODE_RECEIVER: pc_printf("rx"); break;
00539         case 6:
00540             if (Radio::radio.RegOpMode.bits.LongRangeMode)
00541                 pc_printf("rxs");
00542             else
00543                 pc_printf("-6-");
00544             break;  // todo: different lora/fsk
00545         case 7:
00546             if (Radio::radio.RegOpMode.bits.LongRangeMode)
00547                 pc_printf("cad");
00548             else
00549                 pc_printf("-7-");
00550             break;  // todo: different lora/fsk
00551     }
00552 }
00553 #endif /* SX127x_H */
00554 
00555 /*!
00556  * \brief Resets MAC specific parameters to default
00557  */
00558 static void ResetMacParameters( void );
00559 
00560 void
00561 loramac_print_status()
00562 {
00563     int until_beacon = BeaconCtx.rx_setup_at.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count();
00564     mac_printf("until_beacon:%d ", until_beacon);
00565     mac_printf("DR%u=sf%u guard:%d\r\n",
00566         LoRaMacParams.ChannelsDatarate_fixed ,
00567         Datarates[LoRaMacParams.ChannelsDatarate_fixed ],
00568         BeaconCtx.guard
00569     );
00570 #ifdef SX128x_H 
00571     status_t status;
00572     Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
00573     switch (status.bits.cmdStatus) {
00574         case 1: pc_printf("success"); break;
00575         case 2: pc_printf("dataAvail"); break;
00576         case 3: pc_printf("cmdTimeout"); break;
00577         case 4: pc_printf("cmdErr"); break;
00578         case 5: pc_printf("exeFail"); break;
00579         case 6: pc_printf("txdone"); break;
00580         default: pc_printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
00581     }
00582     pc_printf(" ");
00583     switch (status.bits.chipMode) {
00584         case 2: pc_printf("stdby_rc"); break;
00585         case 3: pc_printf("stdby_xosc"); break;
00586         case 4: pc_printf("fs"); break;
00587         case 5: pc_printf("\e[32mrx\e[0m"); break;
00588         case 6: pc_printf("\e[31mtx\e[0m"); break;
00589         default: pc_printf("chipMode:<%u>", status.bits.chipMode); break;
00590     }
00591     LoRaPktPar0_t LoRaPktPar0; 
00592     LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
00593     pc_printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
00594     mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
00595 #elif defined(SX127x_H)
00596     Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG);
00597     if (Radio::radio.RegPaConfig.bits.PaSelect)
00598         pc_printf("PA_BOOST ");
00599     else
00600         pc_printf("RFO ");
00601 
00602     Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
00603     pc_printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
00604     pc_printf("dio0pin:%u ", Radio::radio.dio0.read());
00605     printOpMode();
00606     if (!Radio::radio.RegOpMode.bits.LongRangeMode) {
00607         pc_printf("FSK\r\n");
00608         return;
00609     }
00610 
00611     Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS);
00612     printLoraIrqs(false);
00613 
00614     Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33);     // invert_i_q
00615     Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT);
00616     pc_printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
00617     Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1);
00618     pc_printf("\r\ndio0map:%u\r\n", Radio::radio.RegDioMapping1.bits.Dio0Mapping);
00619     pc_printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
00620 #elif defined(SX126x_H)
00621     status_t status;
00622     Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
00623     switch (status.bits.chipMode) {
00624         case 2: mac_printf("STBY_RC"); break;
00625         case 3: mac_printf("STBY_XOSC"); break;
00626         case 4: mac_printf("FS"); break;
00627         case 5: mac_printf("RX"); break;
00628         case 6: mac_printf("TX"); break;
00629         default: mac_printf("%u", status.bits.chipMode); break;
00630     }
00631     pc_printf(" ");
00632     switch (status.bits.cmdStatus) {
00633         case 1: mac_printf("rfu"); break;
00634         case 2: mac_printf("dataAvail"); break;
00635         case 3: mac_printf("timeout"); break;
00636         case 4: mac_printf("err"); break;
00637         case 5: mac_printf("fail"); break;
00638         case 6: mac_printf("txdone"); break;
00639         default: mac_printf("%u", status.bits.cmdStatus); break;
00640     }
00641     loraConfig0_t conf0;
00642     conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
00643     // bw7=125 bw8=250 b9=500
00644     mac_printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
00645     loraConfig1_t conf1;
00646     conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
00647     mac_printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
00648     mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
00649 #endif /* ..SX126x_H */
00650 }
00651 
00652 static void RxWindowSetup( uint32_t freq, int8_t datarate, uint16_t timeout, bool rxContinuous )
00653 {
00654     uint8_t downlinkDatarate = Datarates[datarate];
00655 
00656     Radio::SetChannel( freq );
00657 
00658     // Store downlink datarate
00659     McpsIndication.RxDatarate  = ( uint8_t ) datarate;
00660 
00661     Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, downlinkDatarate, 1);
00662 
00663                         //    preambleLen, fixLen, crcOn, invIQ
00664     Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, false, true);
00665     Radio::SetLoRaSymbolTimeout(timeout);
00666     Radio::SetRxMaxPayloadLength(LORAMAC_PHY_MAXPAYLOAD);
00667 
00668 } // ..RxWindowSetup()
00669 
00670 static void OnRxWindowTimerEvent( void )
00671 {
00672     RxWindowSetup(Channels[Channel].Frequency, RxWindowsParam.Datarate, RxWindowsParam.RxWindowTimeout, false);
00673     Radio::Rx( LoRaMacParams.MaxRxWindow  );
00674 }
00675 
00676 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError );
00677 
00678 LowPowerClock::time_point rxto_irqAt;
00679 
00680 static void OnRadioTxDone_topHalf()
00681 {
00682     rxto_irqAt = LowPowerClock::now();
00683 }
00684 
00685 static void OnRadioTxDone_bh()
00686 {
00687     // Setup timers
00688     if (IsRxWindowsEnabled)
00689     {
00690         rx_timeout_setAt = rxto_irqAt + RxWindowDelay_us;
00691         rx_timeout.attach_absolute(&OnRxWindowTimerEvent, rx_timeout_setAt);
00692         if (LoRaMacFlags.Bits.NodeAckRequested)
00693         {
00694             microseconds us(ACK_TIMEOUT_us + randr(-ACK_TIMEOUT_RND_us, ACK_TIMEOUT_RND_us));
00695             us += RxWindowDelay_us;
00696             AckTimeoutTimer.attach(&OnAckTimeoutTimerEvent, us - mcu_wakeup_latency);
00697         }
00698     }
00699     else
00700     {
00701         McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
00702         MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
00703 
00704         if( LoRaMacFlags.Value  == 0 )
00705         {
00706             LoRaMacFlags.Bits.McpsReq  = 1;
00707         }
00708         LoRaMacFlags.Bits.MacDone  = 1;
00709     }
00710 
00711     if (!LoRaMacFlags.Bits.NodeAckRequested)
00712     {
00713         McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
00714         ChannelsNbRepCounter++;
00715     }
00716 
00717     MlmeIndication.MlmeIndication = MLME_TXDONE;
00718     MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
00719     LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
00720 
00721     Radio::Standby( );
00722 
00723     txDoneAt = Radio::irqAt /*+ lpt_offset*/;
00724 }
00725 
00726 
00727 static void application_callbacks()
00728 {
00729     if (LoRaMacFlags.Bits.McpsInd ) {
00730         LoRaMacFlags.Bits.McpsInd  = 0;
00731         LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
00732     }
00733 
00734     if (LoRaMacFlags.Bits.McpsReq ) {
00735         LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
00736         LoRaMacFlags.Bits.McpsReq  = 0;
00737     }
00738 }
00739 
00740 static void PrepareRxDoneAbort( void )
00741 {
00742     if (LoRaMacFlags.Bits.NodeAckRequested)
00743     {
00744         OnAckTimeoutTimerEvent( );
00745     }
00746 
00747     LoRaMacFlags.Bits.McpsInd  = 1;
00748     LoRaMacFlags.Bits.MacDone  = 1;
00749 
00750     application_callbacks();
00751 }
00752 
00753 void send_bh()
00754 {
00755     MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
00756     McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND;
00757     McpsConfirm.TxPower  = LoRaMacParams.ChannelsTxPower ;
00758     McpsConfirm.UpLinkFrequency  = Channels[Channel].Frequency ;
00759 
00760     if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)    // joining is channel hunting
00761         Radio::SetChannel( Channels[Channel].Frequency );
00762 
00763     if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
00764     {
00765         JoinRequestTrials++;
00766         mac_printf("join %luhz try%u DR%u\r\n", Channels[Channel].Frequency, JoinRequestTrials, LoRaMacParams.ChannelsDatarate_fixed );
00767     }
00768 
00769     Radio::set_tx_dbm(TxPowers[LoRaMacParams.ChannelsTxPower ]);
00770     Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[LoRaMacParams.ChannelsDatarate_fixed ], 1);
00771 
00772                         //    preambleLen, fixLen, crcOn, invIQ
00773     Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
00774     Radio::Send(tx_buf_len, 0, 0, 0);
00775 
00776     LoRaMacFlags.Bits.uplink_pending = 0;   // sent
00777 
00778     // Compute Rx1 windows parameters, taken at TxDone
00779     if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) {
00780         microseconds us(LoRaMacParams.JoinAcceptDelay_us - TARGET_PRECESSION_us);
00781         RxWindowDelay_us = us - mcu_wakeup_latency;
00782     } else {
00783         microseconds us(LoRaMacParams.ReceiveDelay_us - TARGET_PRECESSION_us);
00784         RxWindowDelay_us = us - mcu_wakeup_latency;
00785     }
00786 
00787 } // ..send_bh()
00788 
00789 void send_callback()
00790 {
00791     LowPowerClock::time_point now = BeaconCtx.sendAt + BeaconCtx.lastSendAtErr;
00792 
00793     if (BeaconCtx.guard) {
00794         /* last send, this will be restarted after beacon sent */
00795         return;
00796     }
00797     BeaconCtx.sendOpportunities++;
00798 
00799     microseconds ping_slot_us(BeaconCtx.periodicity_slots * PING_SLOT_RESOLUTION_us);
00800     BeaconCtx.sendAt += ping_slot_us;
00801     if (BeaconCtx.state == BEACON_STATE_LOCKED) {
00802         float sinceBeacon = now.time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count();
00803         float ratio = sinceBeacon / BEACON_INTERVAL_us;
00804         microseconds duration_err_us((int)(BeaconCtx.last_BeaconRxTimerError_us * ratio));
00805         tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt + duration_err_us - mcu_wakeup_latency);
00806         BeaconCtx.lastSendAtErr = duration_err_us;
00807     } else {
00808         microseconds duration_err_us(0);
00809         tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
00810         BeaconCtx.lastSendAtErr = duration_err_us;
00811     }
00812 
00813     if (LoRaMacFlags.Bits.uplink_pending) {
00814         us_timestamp_t untilGuard = (BeaconCtx.rx_setup_at.time_since_epoch().count() - BEACON_GUARD_us) - LowPowerClock::now().time_since_epoch().count();
00815         if (untilGuard > (RECEIVE_DELAY_us + TARGET_PRECESSION_us))
00816             LoRaMacFlags.Bits.send = 1;
00817     }
00818 }
00819 
00820 void OnRxBeaconSetup()
00821 {
00822     BeaconCtx.guard = false;
00823     LoRaMacFlags.Bits.expecting_beacon = true;
00824 
00825     Radio::Rx(2000);
00826 
00827     BeaconCtx.lastSendAtErr = microseconds(0);
00828 }
00829 
00830 void guard_callback()
00831 {
00832     BeaconCtx.guard = true;
00833     Radio::Standby( );
00834     Radio::SetChannel( Channels[Channel].Frequency );
00835 
00836     tx_timeout.detach();
00837     mac_printf("sendOpportunities:%u\r\n", BeaconCtx.sendOpportunities);
00838     BeaconCtx.sendOpportunities = 0;
00839 
00840                         //    preambleLen, fixLen, crcOn, invIQ
00841     Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false);
00842     Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[BEACON_CHANNEL_DR], 1);
00843     Radio::SetFixedPayloadLength(BEACON_SIZE);
00844 
00845 #ifdef SX128x_H 
00846     /* explicit to implicit header: does sx1280 really need this a 2nd time? */
00847                         //    preambleLen, fixLen, crcOn, invIQ
00848     Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false);
00849 #endif /* SX128x_H */
00850     Radio::SetLoRaSymbolTimeout(BeaconCtx.nSymbsTimeout);
00851 }
00852 
00853 static void us_to_nSymbTimeout(unsigned us)
00854 {
00855     mac_printf("symTo:%u ", us);
00856     BeaconCtx.nSymbsTimeout = us / BeaconCtx.symbol_period_us;
00857     if (BeaconCtx.nSymbsTimeout < (MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols)) {
00858         BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols;
00859     } else if (BeaconCtx.nSymbsTimeout > 255)
00860         BeaconCtx.nSymbsTimeout = 255;
00861 
00862     BeaconCtx.SymbolTimeout_us = BeaconCtx.nSymbsTimeout * BeaconCtx.symbol_period_us;
00863     mac_printf("%u\r\n", BeaconCtx.nSymbsTimeout);
00864 }
00865 
00866 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
00867 {
00868     // The CRC calculation follows CCITT
00869     const uint16_t polynom = 0x1021;
00870     // CRC initial value
00871     uint16_t crc = 0x0000;
00872 
00873     if( buffer == NULL )
00874     {
00875         return 0;
00876     }
00877 
00878     for( uint16_t i = 0; i < length; ++i )
00879     {
00880         crc ^= ( uint16_t ) buffer[i] << 8;
00881         for( uint16_t j = 0; j < 8; ++j )
00882         {
00883             crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
00884         }
00885     }
00886 
00887     return crc;
00888 }
00889 
00890 void rx_beacon(uint16_t size)
00891 {
00892     static bool compensate_precession = false;
00893     int32_t compensation = 0;
00894     /* have beacon end, need beacon start */
00895     microseconds beacon_start_offset_us(BeaconCtx.beaconStartToRxDone);
00896     LowPowerClock::time_point ThisBeaconRxAt = Radio::irqAt - beacon_start_offset_us;
00897 
00898     BeaconCtx.num_consecutive_ok++;
00899     mac_printf("rx_beacon %llu ", Radio::irqAt.time_since_epoch().count());
00900     BeaconCtx.rx_precession_us = ThisBeaconRxAt.time_since_epoch().count() - BeaconCtx.rx_setup_at.time_since_epoch().count();
00901     if (BeaconCtx.state != BEACON_STATE_FIRST_ACQ) {
00902         BeaconCtx.known_working_BeaconRxTimerError_us = BeaconCtx.last_BeaconRxTimerError_us;
00903         BeaconCtx.last_BeaconRxTimerError_us = (ThisBeaconRxAt.time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count()) - (BEACON_INTERVAL_us * (BeaconCtx.num_missed+1));
00904 
00905         if (BeaconCtx.num_missed > 0) {
00906             /* Timer error is measured over more than one beacon period.
00907              * Scale to error seen over single beacon period */
00908             BeaconCtx.last_BeaconRxTimerError_us /= BeaconCtx.num_missed + 1;
00909         }
00910 
00911         if (BeaconCtx.state == BEACON_STATE_ACQ_ERROR) {
00912             mac_printf("-->LOCKED ");
00913             BeaconCtx.state = BEACON_STATE_LOCKED;
00914             compensate_precession = true;
00915         }
00916     } else {
00917         /* ignore precession at first acquisition because it has slot resolution added */
00918         mac_printf("-->ACQ_ERROR ");
00919         // next beacon will give us our crystal error
00920         BeaconCtx.state = BEACON_STATE_ACQ_ERROR;
00921     }
00922 
00923     mac_printf("err%d=%llu-%llu ", BeaconCtx.last_BeaconRxTimerError_us, ThisBeaconRxAt.time_since_epoch().count(), BeaconCtx.LastBeaconRxAt.time_since_epoch().count());
00924     if (BeaconCtx.num_missed > 0)
00925         mac_printf("missed%u ", BeaconCtx.num_missed);
00926 
00927     mac_printf(" rx-before-tx:%d ", BeaconCtx.rx_precession_us);
00928     if (BeaconCtx.last_BeaconRxTimerError_us > 40000 || BeaconCtx.last_BeaconRxTimerError_us < -40000) {
00929         BeaconCtx.timeout_rx.detach();
00930         BeaconCtx.timeout_guard.detach();
00931         mac_printf("halt\r\n");
00932         for (;;) asm("nop");
00933     }
00934     BeaconCtx.LastBeaconRxAt = ThisBeaconRxAt;
00935 
00936     if (BeaconCtx.state == BEACON_STATE_LOCKED) {
00937         if (compensate_precession) {
00938             compensation = BeaconCtx.rx_precession_us - TARGET_PRECESSION_us + BeaconCtx.last_BeaconRxTimerError_us;
00939             mac_printf(" comp%ld", compensation);
00940         }
00941     }
00942 
00943     // reference tick for uplink schedule: when gateway started beacon
00944     microseconds send_offset_us(BeaconCtx.rx_precession_us + (BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us));
00945     BeaconCtx.sendAt = BeaconCtx.rx_setup_at + send_offset_us;
00946     tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
00947     mac_printf("sendAt:%llu ", BeaconCtx.sendAt.time_since_epoch().count());
00948 
00949     microseconds us_to_next_beacon(BEACON_INTERVAL_us + compensation);
00950     BeaconCtx.rx_setup_at += us_to_next_beacon;
00951 
00952     BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
00953     microseconds beacon_guard_us(BEACON_GUARD_us);
00954     BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - beacon_guard_us - mcu_wakeup_latency);
00955 
00956     BeaconCtx.num_missed = 0;
00957 
00958     MlmeIndication.MlmeIndication = MLME_BEACON;
00959     MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED;
00960     LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
00961 
00962     /* check beacon payload */
00963     uint16_t calc_crc = beacon_crc(Radio::radio.rx_buf, 4);
00964     uint16_t rx_crc = Radio::radio.rx_buf[4];
00965     rx_crc |= Radio::radio.rx_buf[5] << 8;
00966     if (rx_crc == calc_crc) {
00967         unsigned int rx = Radio::radio.rx_buf[0];
00968         rx |= Radio::radio.rx_buf[1] << 8;
00969         rx |= Radio::radio.rx_buf[2] << 16;
00970         rx |= Radio::radio.rx_buf[3] << 24;
00971         if (rx != 0) {
00972             McpsIndication.McpsIndication  = MCPS_MULTICAST;
00973             McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
00974             McpsIndication.Buffer  = Radio::radio.rx_buf;
00975             McpsIndication.BufferSize  = 4;
00976             McpsIndication.RxData  = true;
00977             LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
00978         }
00979     } else
00980         mac_printf("calc_crc:%04x rx_crc:%04x\r\n", calc_crc, rx_crc);
00981 } // ..rx_beacon()
00982 
00983 
00984 #define JOIN_ACCEPT_MAX_SIZE        34
00985 static void OnRadioRxDone(uint8_t size, float rssi, float snr )
00986 {
00987     uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
00988     LoRaMacHeader_t  macHdr;
00989     LoRaMacFrameCtrl_t  fCtrl;
00990     bool skipIndication = false;
00991 
00992     uint8_t pktHeaderLen = 0;
00993     uint32_t address = 0;
00994     uint8_t appPayloadStartIndex = 0;
00995     uint8_t port = 0xFF;
00996     uint8_t frameLen = 0;
00997     uint32_t mic = 0;
00998     uint32_t micRx = 0;
00999 
01000     uint16_t sequenceCounter = 0;
01001     uint16_t sequenceCounterPrev = 0;
01002     uint16_t sequenceCounterDiff = 0;
01003     uint32_t downLinkCounter = 0;
01004 
01005     MulticastParams_t  *curMulticastParams = NULL;
01006     uint8_t *nwkSKey = LoRaMacNwkSKey;
01007     uint8_t *appSKey = LoRaMacAppSKey;
01008 
01009     uint8_t multicast = 0;
01010 
01011     bool isMicOk = false;
01012 
01013     McpsConfirm.AckReceived  = false;
01014     McpsIndication.Rssi  = rssi;
01015     McpsIndication.Snr  = snr;
01016     McpsIndication.Port  = 0;
01017     McpsIndication.Multicast  = 0;
01018     McpsIndication.FramePending  = 0;
01019     McpsIndication.Buffer  = NULL;
01020     McpsIndication.BufferSize  = 0;
01021     McpsIndication.RxData  = false;
01022     McpsIndication.AckReceived  = false;
01023     McpsIndication.DownLinkCounter  = 0;
01024     McpsIndication.McpsIndication  = MCPS_UNCONFIRMED;
01025 
01026     Radio::Sleep( );
01027 
01028     if (LoRaMacFlags.Bits.expecting_beacon) {
01029         rx_beacon(size);
01030         LoRaMacFlags.Bits.expecting_beacon = false;
01031         return;
01032     }
01033 
01034     macHdr.Value  = Radio::radio.rx_buf[pktHeaderLen++];
01035 
01036     switch( macHdr.Bits.MType  )
01037     {
01038         case FRAME_TYPE_JOIN_ACCEPT:
01039             if (LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
01040             {
01041                 McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT;
01042                 PrepareRxDoneAbort( );
01043                 return;
01044             }
01045             LoRaMacJoinDecrypt ( Radio::radio.rx_buf + 1, size - 1, LoRaMacAppKey, &_jaDecrypted[1]);
01046 
01047             _jaDecrypted[0] = macHdr.Value ;
01048 
01049             LoRaMacJoinComputeMic ( _jaDecrypted, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
01050 
01051             micRx |= ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN];
01052             micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 1] << 8 );
01053             micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 2] << 16 );
01054             micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 3] << 24 );
01055 
01056             if( micRx == mic )
01057             {
01058                 uint32_t beaconDur;
01059                 LoRaMacJoinComputeSKeys ( LoRaMacAppKey, _jaDecrypted + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
01060 
01061                 LoRaMacNetID = ( uint32_t )_jaDecrypted[4];
01062                 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[5] << 8 );
01063                 LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[6] << 16 );
01064 
01065                 LoRaMacDevAddr = ( uint32_t )_jaDecrypted[7];
01066                 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[8] << 8 );
01067                 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[9] << 16 );
01068                 LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[10] << 24 );
01069 
01070                 // DLSettings
01071                 LoRaMacParams.Rx1DrOffset  = ( _jaDecrypted[11] >> 4 ) & 0x07;
01072 
01073                 LoRaMacParams.ReceiveDelay_us = ( _jaDecrypted[12] & 0x0F );
01074                 if( LoRaMacParams.ReceiveDelay_us == 0 )
01075                     LoRaMacParams.ReceiveDelay_us = RECEIVE_DELAY_us;
01076                 else
01077                     LoRaMacParams.ReceiveDelay_us *= 10;
01078 
01079                 uint16_t beaconTimingDelay = _jaDecrypted[13] & 0xff;
01080                 beaconTimingDelay |= _jaDecrypted[14] << 8;
01081 
01082                 mac_printf("%lx slots:%x (rxdelay %lu)", LoRaMacDevAddr, beaconTimingDelay, LoRaMacParams.ReceiveDelay_us);
01083                 {
01084                     unsigned us_to_beacon = ( PING_SLOT_RESOLUTION_us * beaconTimingDelay );
01085                     mac_printf(" us_to_beacon:%u ", us_to_beacon);
01086                     // time to beacon given as referenced to end of join request uplink
01087                     microseconds tx_done_to_rx_start_us(us_to_beacon - PPM_BEACON_INTERVAL);
01088                     BeaconCtx.rx_setup_at = txDoneAt + tx_done_to_rx_start_us;
01089                     BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
01090                     microseconds beacon_guard_us(BEACON_GUARD_us);
01091                     BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - (beacon_guard_us + mcu_wakeup_latency));
01092 
01093                     mac_printf("beaconIn:%llu\r\n", BeaconCtx.rx_setup_at.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count());
01094                 }
01095 
01096                 BeaconCtx.tx_slot_offset = _jaDecrypted[15];
01097                 BeaconCtx.tx_slot_offset |= _jaDecrypted[16] << 8;
01098                 BeaconCtx.periodicity_slots = _jaDecrypted[17];
01099                 BeaconCtx.periodicity_slots |= _jaDecrypted[18] << 8;
01100 
01101                 beaconDur = _jaDecrypted[22];
01102                 beaconDur <<= 8;
01103                 beaconDur |= _jaDecrypted[21];
01104                 beaconDur <<= 8;
01105                 beaconDur |= _jaDecrypted[20];
01106                 beaconDur <<= 8;
01107                 beaconDur |= _jaDecrypted[19];
01108                 BeaconCtx.beaconStartToRxDone = beaconDur + (rxLatencyFactorFromSF[SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE)-FASTEST_SF] * BeaconCtx.symbol_period_us);
01109 
01110 
01111                 /* nowSlot: now vs previous beacon */
01112                 microseconds beacon_interval_us(BEACON_INTERVAL_us);
01113                 BeaconCtx.LastBeaconRxAt = BeaconCtx.rx_setup_at - beacon_interval_us;
01114                 unsigned us_since_last_beacon = LowPowerClock::now().time_since_epoch().count() - BeaconCtx.LastBeaconRxAt.time_since_epoch().count();
01115                 unsigned nowSlot = us_since_last_beacon / PING_SLOT_RESOLUTION_us;
01116                 unsigned useSlot = BeaconCtx.tx_slot_offset;
01117                 while (useSlot < nowSlot)
01118                     useSlot += BeaconCtx.periodicity_slots;
01119 
01120                 mac_printf("beaconDur:0x%lx (%lu) useSlot:%u nowSlot:%u ", beaconDur, BeaconCtx.beaconStartToRxDone, useSlot, nowSlot);
01121                 microseconds ping_slot_offset_us(useSlot * PING_SLOT_RESOLUTION_us);
01122                 BeaconCtx.sendAt = BeaconCtx.LastBeaconRxAt + ping_slot_offset_us;
01123 
01124                 mac_printf("sendIn:%lld\r\n", BeaconCtx.sendAt.time_since_epoch().count() - LowPowerClock::now().time_since_epoch().count());
01125                 tx_timeout.attach_absolute(send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
01126                 BeaconCtx.sendOpportunities = 0;
01127 
01128                 BeaconCtx.state = BEACON_STATE_FIRST_ACQ;
01129                 BeaconCtx.guard = false;
01130                 BeaconCtx.num_missed = 0;
01131                 BeaconCtx.rx_precession_us = 0;
01132                 BeaconCtx.num_consecutive_ok = 0;
01133                 BeaconCtx.last_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
01134                 BeaconCtx.known_working_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL;
01135                 /* first beacon reception needs to open for 30ms timing resolution */
01136                 BeaconCtx.Precess_symbols = ceil((float)(TARGET_PRECESSION_us / BeaconCtx.symbol_period_us));
01137                 BeaconCtx.SymbolTimeout_us = PING_SLOT_RESOLUTION_us + (PPM_BEACON_INTERVAL * 4);   // error unknown at start
01138                 BeaconCtx.nSymbsTimeout = BeaconCtx.SymbolTimeout_us / BeaconCtx.symbol_period_us;
01139                 if (BeaconCtx.nSymbsTimeout < MIN_SYMBOL_TIMEOUT)
01140                     BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT;
01141                 else if (BeaconCtx.nSymbsTimeout > 255)
01142                     BeaconCtx.nSymbsTimeout = 255;
01143                 mac_printf("startSymbTo:%u ", BeaconCtx.nSymbsTimeout);
01144 
01145                 MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
01146                 LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = true;
01147                 LoRaMacParams.ChannelsDatarate_fixed  = LoRaMacParamsDefaults.ChannelsDatarate_fixed ;
01148             }
01149             else
01150             {
01151                 MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
01152                 mac_printf("join-mic-fail size:%u\r\n", size);
01153                 JoinRequestTrials = MaxJoinRequestTrials; // stop trying
01154             }
01155             LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
01156             LoRaMacFlags.Bits.MlmeReq  = 0;  // MacMlmeConfirm() called
01157             break;
01158         case FRAME_TYPE_DATA_CONFIRMED_DOWN:
01159         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
01160             {
01161                 address = Radio::radio.rx_buf[pktHeaderLen++];
01162                 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 8 );
01163                 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 16 );
01164                 address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 24 );
01165 
01166                 if( address != LoRaMacDevAddr )
01167                 {
01168                     curMulticastParams = MulticastChannels;
01169                     while( curMulticastParams != NULL )
01170                     {
01171                         if( address == curMulticastParams->Address  )
01172                         {
01173                             multicast = 1;
01174                             nwkSKey = curMulticastParams->NwkSKey ;
01175                             appSKey = curMulticastParams->AppSKey ;
01176                             downLinkCounter = curMulticastParams->DownLinkCounter ;
01177                             break;
01178                         }
01179                         curMulticastParams = curMulticastParams->Next ;
01180                     }
01181                     if( multicast == 0 )
01182                     {
01183                         // We are not the destination of this frame.
01184                         McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
01185                         PrepareRxDoneAbort( );
01186                         return;
01187                     }
01188                 }
01189                 else
01190                 {
01191                     multicast = 0;
01192                     nwkSKey = LoRaMacNwkSKey;
01193                     appSKey = LoRaMacAppSKey;
01194                     downLinkCounter = DownLinkCounter;
01195                 }
01196 
01197                 fCtrl.Value  = Radio::radio.rx_buf[pktHeaderLen++];
01198 
01199                 sequenceCounter = ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++];
01200                 sequenceCounter |= ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++] << 8;
01201 
01202                 appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen ;
01203 
01204                 micRx |= ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN];
01205                 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 1] << 8 );
01206                 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 2] << 16 );
01207                 micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 3] << 24 );
01208 
01209                 sequenceCounterPrev = ( uint16_t )downLinkCounter;
01210                 sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
01211 
01212                 if( sequenceCounterDiff < ( 1 << 15 ) )
01213                 {
01214                     downLinkCounter += sequenceCounterDiff;
01215                     LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
01216                     if( micRx == mic )
01217                     {
01218                         isMicOk = true;
01219                     }
01220                 }
01221                 else
01222                 {
01223                     // check for sequence roll-over
01224                     uint32_t  downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
01225                     LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
01226                     if( micRx == mic )
01227                     {
01228                         isMicOk = true;
01229                         downLinkCounter = downLinkCounterTmp;
01230                     }
01231                 }
01232 
01233                 // Check for a the maximum allowed counter difference
01234                 if( sequenceCounterDiff >= MAX_FCNT_GAP )
01235                 {
01236                     McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
01237                     McpsIndication.DownLinkCounter  = downLinkCounter;
01238                     PrepareRxDoneAbort( );
01239                     return;
01240                 }
01241 
01242                 if( isMicOk == true )
01243                 {
01244                     McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
01245                     McpsIndication.Multicast  = multicast;
01246                     McpsIndication.FramePending  = fCtrl.Bits.FPending ;
01247                     McpsIndication.Buffer  = NULL;
01248                     McpsIndication.BufferSize  = 0;
01249                     McpsIndication.DownLinkCounter  = downLinkCounter;
01250 
01251                     McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
01252 
01253                     MacCommandsBufferToRepeatIndex = 0;
01254 
01255                     // Update 32 bits downlink counter
01256                     if( multicast == 1 )
01257                     {
01258                         McpsIndication.McpsIndication  = MCPS_MULTICAST;
01259 
01260                         if( ( curMulticastParams->DownLinkCounter  == downLinkCounter ) &&
01261                             ( curMulticastParams->DownLinkCounter  != 0 ) )
01262                         {
01263                             McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
01264                             McpsIndication.DownLinkCounter  = downLinkCounter;
01265                             PrepareRxDoneAbort( );
01266                             return;
01267                         }
01268                         curMulticastParams->DownLinkCounter  = downLinkCounter;
01269                     }
01270                     else
01271                     {
01272                         if( macHdr.Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_DOWN )
01273                         {
01274                             LoRaMacFlags.Bits.SrvAckRequested = true;
01275                             McpsIndication.McpsIndication  = MCPS_CONFIRMED;
01276 
01277                             if( ( DownLinkCounter == downLinkCounter ) &&
01278                                 ( DownLinkCounter != 0 ) )
01279                             {
01280                                 // Duplicated confirmed downlink. Skip indication.
01281                                 // In this case, the MAC layer shall accept the MAC commands
01282                                 // which are included in the downlink retransmission.
01283                                 // It should not provide the same frame to the application
01284                                 // layer again.
01285                                 skipIndication = true;
01286                             }
01287                         }
01288                         else
01289                         {
01290                             LoRaMacFlags.Bits.SrvAckRequested = false;
01291                             McpsIndication.McpsIndication  = MCPS_UNCONFIRMED;
01292 
01293                             if( ( DownLinkCounter == downLinkCounter ) &&
01294                                 ( DownLinkCounter != 0 ) )
01295                             {
01296                                 McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
01297                                 McpsIndication.DownLinkCounter  = downLinkCounter;
01298                                 PrepareRxDoneAbort( );
01299                                 return;
01300                             }
01301                         }
01302                         DownLinkCounter = downLinkCounter;
01303                     }
01304 
01305                     // This must be done before parsing the payload and the MAC commands.
01306                     // We need to reset the MacCommandsBufferIndex here, since we need
01307                     // to take retransmissions and repititions into account. Error cases
01308                     // will be handled in function OnMacStateCheckTimerEvent.
01309                     if( McpsConfirm.McpsRequest  == MCPS_CONFIRMED )
01310                     {
01311                         if( fCtrl.Bits.Ack  == 1 )
01312                         {// Reset MacCommandsBufferIndex when we have received an ACK.
01313                             MacCommandsBufferIndex = 0;
01314                         }
01315                     }
01316                     else
01317                     {// Reset the variable if we have received any valid frame.
01318                         MacCommandsBufferIndex = 0;
01319                     }
01320 
01321                     // Process payload and MAC commands
01322                     if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
01323                     {
01324                         port = Radio::radio.rx_buf[appPayloadStartIndex++];
01325                         frameLen = ( size - 4 ) - appPayloadStartIndex;
01326 
01327                         McpsIndication.Port  = port;
01328 
01329                         if( port == 0 )
01330                         {
01331                             // Only allow frames which do not have fOpts
01332                             if( fCtrl.Bits.FOptsLen  == 0 )
01333                             {
01334                                 uint8_t macDecrypt[16];
01335                                 LoRaMacPayloadDecrypt ( Radio::radio.rx_buf + appPayloadStartIndex,
01336                                                        frameLen,
01337                                                        nwkSKey,
01338                                                        address,
01339                                                        DOWN_LINK,
01340                                                        downLinkCounter,
01341                                                        macDecrypt);
01342 
01343                                 // Decode frame payload MAC commands
01344                                 ProcessMacCommands( macDecrypt, 0, frameLen, snr );
01345                             }
01346                             else
01347                             {
01348                                 skipIndication = true;
01349                             }
01350                         }
01351                         else
01352                         {
01353                             if( fCtrl.Bits.FOptsLen  > 0 )
01354                             {
01355                                 // Decode Options field MAC commands. Omit the fPort.
01356                                 ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex - 1, snr );
01357                             }
01358 
01359                             LoRaMacPayloadDecrypt ( Radio::radio.rx_buf + appPayloadStartIndex,
01360                                                    frameLen,
01361                                                    appSKey,
01362                                                    address,
01363                                                    DOWN_LINK,
01364                                                    downLinkCounter,
01365                                                    rxFRMPayload);
01366 
01367                             if( skipIndication == false )
01368                             {
01369                                 McpsIndication.Buffer  = rxFRMPayload;
01370                                 McpsIndication.BufferSize  = frameLen;
01371                                 McpsIndication.RxData  = true;
01372                             }
01373                         }
01374                     }
01375                     else
01376                     {
01377                         if( fCtrl.Bits.FOptsLen  > 0 )
01378                         {
01379                             // Decode Options field MAC commands
01380                             ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex, snr );
01381                         }
01382                     }
01383 
01384                     if( skipIndication == false )
01385                     {
01386                         // Check if the frame is an acknowledgement
01387                         if( fCtrl.Bits.Ack  == 1 )
01388                         {
01389                             McpsConfirm.AckReceived  = true;
01390                             McpsIndication.AckReceived  = true;
01391 
01392                             // Stop the AckTimeout timer as no more retransmissions
01393                             // are needed.
01394                         }
01395                         else
01396                         {
01397                             McpsConfirm.AckReceived  = false;
01398                         }
01399                     }
01400                     // Provide always an indication, skip the callback to the user application,
01401                     // in case of a confirmed downlink retransmission.
01402                     LoRaMacFlags.Bits.McpsInd  = 1;
01403                     LoRaMacFlags.Bits.McpsIndSkip  = skipIndication;
01404                 }
01405                 else
01406                 {
01407                     McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
01408                     McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
01409                     PrepareRxDoneAbort( );
01410                     return;
01411                 }
01412             }
01413             break;
01414         case FRAME_TYPE_PROPRIETARY:
01415             {
01416                 McpsIndication.McpsIndication  = MCPS_PROPRIETARY;
01417                 McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
01418                 McpsIndication.Buffer  = Radio::radio.rx_buf;
01419                 McpsIndication.BufferSize  = size - pktHeaderLen;
01420 
01421                 LoRaMacFlags.Bits.McpsInd  = 1;
01422                 break;
01423             }
01424         default:
01425             McpsIndication.Status  = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
01426             McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE;
01427             mac_printf("%d:macHdr:%02x(%f,%f) ", size, macHdr.Value , rssi, snr);
01428             PrepareRxDoneAbort( );
01429             break;
01430     }
01431     LoRaMacFlags.Bits.MacDone  = 1;
01432 
01433     application_callbacks();
01434 
01435 } // ..OnRadioRxDone()
01436 
01437 static void OnRadioTxTimeout( void )
01438 {
01439     Radio::Sleep( );
01440 
01441     McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
01442     MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
01443     LoRaMacFlags.Bits.MacDone  = 1;
01444 }
01445 
01446 static void OnRadioRxError( void )
01447 {
01448     Radio::Sleep( );
01449 
01450     if (LoRaMacFlags.Bits.NodeAckRequested)
01451     {
01452         McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
01453     }
01454     MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
01455 
01456     LoRaMacFlags.Bits.MacDone  = 1;
01457 }
01458 
01459 static void
01460 join_send()
01461 {
01462     LoRaMacFlags.Bits.join_send = 1;
01463 }
01464 
01465 static void ScheduleTx( void )
01466 {
01467     if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
01468         LoRaMacFlags.Bits.send = 1; // immediately send join asychronously
01469     else
01470         LoRaMacFlags.Bits.uplink_pending = 1;   // send synchronously
01471 }
01472 
01473 static void
01474 join_send_bh()
01475 {
01476     if (JoinRequestTrials < MaxJoinRequestTrials) {
01477         LoRaMacHeader_t  macHdr;
01478         LoRaMacFrameCtrl_t  fCtrl;
01479 
01480         if (++Channel == LORA_MAX_NB_CHANNELS)
01481             Channel = 0;
01482         mac_printf("<join-ch%u>", Channel);
01483 
01484         macHdr.Value  = 0;
01485         macHdr.Bits.MType  = FRAME_TYPE_JOIN_REQ;
01486 
01487         fCtrl.Value  = 0;
01488         fCtrl.Bits.Adr  = 0;
01489 
01490         /* In case of join request retransmissions, the stack must prepare
01491          * the frame again, because the network server keeps track of the random
01492          * LoRaMacDevNonce values to prevent reply attacks. */
01493         PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
01494 
01495         ScheduleTx();
01496     } else {
01497         MlmeConfirm.MlmeRequest  = MLME_JOIN;
01498         MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
01499         LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
01500     }
01501 } // ..join_send_bh()
01502 
01503 static void OnRadioRxTimeout( void )
01504 {
01505     Radio::Sleep( );
01506 
01507     pc_printf("OnRadioRxTimeout eb%u\r\n", LoRaMacFlags.Bits.expecting_beacon);
01508     if (LoRaMacFlags.Bits.expecting_beacon) {
01509         float ourErrSecs = BeaconCtx.known_working_BeaconRxTimerError_us / 1000000.0;
01510 
01511         LoRaMacFlags.Bits.expecting_beacon = false;
01512 
01513         microseconds rx_next_us(BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us);
01514         BeaconCtx.rx_setup_at += rx_next_us;
01515         microseconds pre_rx_us(PPM_BEACON_INTERVAL / 4); // come up early when missed
01516         BeaconCtx.rx_setup_at -= pre_rx_us;
01517         us_to_nSymbTimeout(BeaconCtx.SymbolTimeout_us + PPM_BEACON_INTERVAL);
01518         mac_printf("beacon timeout ourErr:%f SymbTo:%u(%uus)\r\n", ourErrSecs, BeaconCtx.nSymbsTimeout, BeaconCtx.SymbolTimeout_us);
01519 
01520         BeaconCtx.timeout_rx.attach_absolute(&OnRxBeaconSetup, BeaconCtx.rx_setup_at - mcu_wakeup_latency);
01521         microseconds guard_us(BEACON_GUARD_us);
01522         BeaconCtx.timeout_guard.attach_absolute(&guard_callback, BeaconCtx.rx_setup_at - (guard_us + mcu_wakeup_latency));
01523 
01524         if (++BeaconCtx.num_missed > BEACONS_MISSED_LIMIT) {
01525             LoRaMacFlags.Bits.reJoin = 1;
01526         } else {
01527             MlmeIndication.MlmeIndication = MLME_BEACON;
01528             MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOST;
01529             LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
01530         }
01531 
01532         microseconds base((BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us) * BeaconCtx.num_missed);
01533         BeaconCtx.sendAt = BeaconCtx.LastBeaconRxAt + base;
01534         microseconds tx_slot_us(BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us);
01535         BeaconCtx.sendAt += tx_slot_us;
01536         tx_timeout.attach_absolute(&send_callback, BeaconCtx.sendAt - mcu_wakeup_latency);
01537 
01538         BeaconCtx.num_consecutive_ok = 0;
01539     } else {
01540         if (LoRaMacFlags.Bits.MlmeReq  && ( MlmeConfirm.MlmeRequest  == MLME_JOIN )) {
01541             /* no join accept received: join retry */
01542             microseconds us((JoinRequestTrials*20000) + randr(0, 70000));
01543             tx_timeout.attach(&join_send, us - mcu_wakeup_latency);
01544         }
01545     }
01546 
01547     if (LoRaMacFlags.Bits.NodeAckRequested)
01548     {
01549         McpsConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
01550     }
01551     MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
01552     LoRaMacFlags.Bits.MacDone  = 1;
01553 
01554     application_callbacks();
01555 } // ..OnRadioRxTimeout();
01556 
01557 static void OnAckTimeoutTimerEvent( void )
01558 {
01559 }
01560 
01561 static bool ValueInRange( int8_t value, int8_t min, int8_t max )
01562 {
01563     if( ( value >= min ) && ( value <= max ) )
01564     {
01565         return true;
01566     }
01567     return false;
01568 }
01569 
01570 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
01571 {
01572     LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
01573     // The maximum buffer length must take MAC commands to re-send into account.
01574     uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
01575 
01576     switch( cmd )
01577     {
01578         case MOTE_MAC_LINK_CHECK_REQ:
01579             if( MacCommandsBufferIndex < bufLen )
01580             {
01581                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
01582                 // No payload for this command
01583                 status = LORAMAC_STATUS_OK;
01584             }
01585             break;
01586         case MOTE_MAC_RX_PARAM_SETUP_ANS:
01587             if( MacCommandsBufferIndex < ( bufLen - 1 ) )
01588             {
01589                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
01590                 // Status: Datarate ACK, Channel ACK
01591                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
01592                 status = LORAMAC_STATUS_OK;
01593             }
01594             break;
01595         case MOTE_MAC_DEV_STATUS_ANS:
01596             if( MacCommandsBufferIndex < ( bufLen - 2 ) )
01597             {
01598                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
01599                 // 1st byte Battery
01600                 // 2nd byte Margin
01601                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
01602                 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
01603                 status = LORAMAC_STATUS_OK;
01604             }
01605             break;
01606         case MOTE_MAC_RX_TIMING_SETUP_ANS:
01607             if( MacCommandsBufferIndex < bufLen )
01608             {
01609                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
01610                 // No payload for this answer
01611                 status = LORAMAC_STATUS_OK;
01612             }
01613             break;
01614         default:
01615             return LORAMAC_STATUS_SERVICE_UNKNOWN;
01616     }
01617     if( status == LORAMAC_STATUS_OK )
01618     {
01619         MacCommandsInNextTx = true;
01620     }
01621     return status;
01622 }
01623 
01624 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut )
01625 {
01626     uint8_t i = 0;
01627     uint8_t cmdCount = 0;
01628 
01629     if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) )
01630     {
01631         return 0;
01632     }
01633 
01634     for( i = 0; i < length; i++ )
01635     {
01636         switch( cmdBufIn[i] )
01637         {
01638             // STICKY
01639             case MOTE_MAC_RX_PARAM_SETUP_ANS:
01640             {
01641                 cmdBufOut[cmdCount++] = cmdBufIn[i++];
01642                 cmdBufOut[cmdCount++] = cmdBufIn[i];
01643                 break;
01644             }
01645             case MOTE_MAC_RX_TIMING_SETUP_ANS:
01646             {
01647                 cmdBufOut[cmdCount++] = cmdBufIn[i];
01648                 break;
01649             }
01650             // NON-STICKY
01651             case MOTE_MAC_DEV_STATUS_ANS:
01652             { // 2 bytes payload
01653                 i += 2;
01654                 break;
01655             }
01656             case MOTE_MAC_LINK_CHECK_REQ:
01657             { // 0 byte payload
01658                 break;
01659             }
01660             default:
01661                 break;
01662         }
01663     }
01664 
01665     return cmdCount;
01666 }
01667 
01668 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
01669 {
01670     while( macIndex < commandsSize )
01671     {
01672         // Decode Frame MAC commands
01673         switch( payload[macIndex++] )
01674         {
01675             case SRV_MAC_LINK_CHECK_ANS:
01676                 MlmeConfirm.Status  = LORAMAC_EVENT_INFO_STATUS_OK;
01677                 MlmeConfirm.DemodMargin  = payload[macIndex++];
01678                 MlmeConfirm.NbGateways  = payload[macIndex++];
01679                 break;
01680             case SRV_MAC_DEV_STATUS_REQ:
01681                 {
01682                     uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
01683                     if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
01684                     {
01685                         batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
01686                     }
01687                     AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
01688                     break;
01689                 }
01690             case SRV_MAC_RX_TIMING_SETUP_REQ:
01691                 {
01692                     uint8_t delay = payload[macIndex++] & 0x0F;
01693 
01694                     if( delay == 0 )
01695                     {
01696                         delay++;
01697                     }
01698                     LoRaMacParams.ReceiveDelay_us = delay * 1e6;
01699                     AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
01700                 }
01701                 break;
01702             default:
01703                 // Unknown command. ABORT MAC commands processing
01704                 return;
01705         }
01706     }
01707 }
01708 
01709 LoRaMacStatus_t Send( LoRaMacHeader_t  *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
01710 {
01711     LoRaMacFrameCtrl_t  fCtrl;
01712     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
01713 
01714     fCtrl.Value  = 0;
01715     fCtrl.Bits.FOptsLen       = 0;
01716     fCtrl.Bits.FPending       = 0;
01717     fCtrl.Bits.Ack            = false;
01718     fCtrl.Bits.AdrAckReq      = false;
01719     fCtrl.Bits.Adr            = false;
01720 
01721     // Prepare the frame
01722     status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
01723 
01724     // Validate status
01725     if( status != LORAMAC_STATUS_OK )
01726     {
01727         return status;
01728     }
01729 
01730     // Reset confirm parameters
01731     McpsConfirm.AckReceived  = false;
01732     McpsConfirm.UpLinkCounter  = UpLinkCounter;
01733 
01734     ScheduleTx();
01735 
01736     return LORAMAC_STATUS_OK;
01737 }
01738 
01739 
01740 static void ResetMacParameters( void )
01741 {
01742     LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = false;
01743 
01744     // Counters
01745     UpLinkCounter = 0;
01746     DownLinkCounter = 0;
01747 
01748     ChannelsNbRepCounter = 0;
01749 
01750     MacCommandsBufferIndex = 0;
01751     MacCommandsBufferToRepeatIndex = 0;
01752 
01753     IsRxWindowsEnabled = true;
01754 
01755     LoRaMacParams.ChannelsTxPower  = LoRaMacParamsDefaults.ChannelsTxPower ;
01756     LoRaMacParams.ChannelsDatarate_fixed  = LoRaMacParamsDefaults.ChannelsDatarate_fixed ;
01757 
01758     LoRaMacParams.Rx1DrOffset  = LoRaMacParamsDefaults.Rx1DrOffset ;
01759 
01760     LoRaMacFlags.Bits.NodeAckRequested = false;
01761     LoRaMacFlags.Bits.SrvAckRequested = false;
01762     MacCommandsInNextTx = false;
01763 
01764     // Reset Multicast downlink counters
01765     MulticastParams_t  *cur = MulticastChannels;
01766     while( cur != NULL )
01767     {
01768         cur->DownLinkCounter  = 0;
01769         cur = cur->Next ;
01770     }
01771 
01772 }
01773 
01774 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t  *macHdr, LoRaMacFrameCtrl_t  *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
01775 {
01776     uint16_t i;
01777     uint32_t mic = 0;
01778     const void* payload = fBuffer;
01779     uint8_t framePort = fPort;
01780     uint8_t LoRaMacTxPayloadLen = 0;
01781 
01782     LoRaMacFlags.Bits.NodeAckRequested = false;
01783     tx_buf_len = 0;
01784 
01785     if( fBuffer == NULL )
01786     {
01787         fBufferSize = 0;
01788     }
01789 
01790     LoRaMacTxPayloadLen = fBufferSize;
01791 
01792     Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value ;
01793 
01794     switch( macHdr->Bits.MType  )
01795     {
01796         case FRAME_TYPE_JOIN_REQ:
01797             memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacAppEui, 8 );
01798             tx_buf_len += 8;
01799             memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
01800             tx_buf_len += 8;
01801 
01802             LoRaMacDevNonce = Radio::Random( );
01803 
01804             Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
01805             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
01806 
01807             LoRaMacJoinComputeMic ( Radio::radio.tx_buf, tx_buf_len & 0xFF, LoRaMacAppKey, &mic );
01808 
01809             Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
01810             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
01811             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
01812             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
01813 
01814             break;
01815         case FRAME_TYPE_DATA_CONFIRMED_UP:
01816             LoRaMacFlags.Bits.NodeAckRequested = true;
01817             //Intentional fallthrough
01818         case FRAME_TYPE_DATA_UNCONFIRMED_UP:
01819             if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined)
01820             {
01821                 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
01822             }
01823 
01824             fCtrl->Bits.AdrAckReq  = 0;
01825 
01826             if( LoRaMacFlags.Bits.SrvAckRequested == true )
01827             {
01828                 LoRaMacFlags.Bits.SrvAckRequested = false;
01829                 fCtrl->Bits.Ack  = 1;
01830             }
01831 
01832             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF;
01833             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
01834             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
01835             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
01836 
01837             Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value ;
01838 
01839             Radio::radio.tx_buf[tx_buf_len++] = UpLinkCounter & 0xFF;
01840             Radio::radio.tx_buf[tx_buf_len++] = ( UpLinkCounter >> 8 ) & 0xFF;
01841 
01842             // Copy the MAC commands which must be re-send into the MAC command buffer
01843             memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
01844             MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
01845 
01846             if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
01847             {
01848                 if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
01849                 {
01850                     fCtrl->Bits.FOptsLen  += MacCommandsBufferIndex;
01851 
01852                     // Update FCtrl field with new value of OptionsLength
01853                     Radio::radio.tx_buf[0x05] = fCtrl->Value ;
01854                     for( i = 0; i < MacCommandsBufferIndex; i++ )
01855                     {
01856                         Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i];
01857                     }
01858                 }
01859             }
01860             else
01861             {
01862                 if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
01863                 {
01864                     LoRaMacTxPayloadLen = MacCommandsBufferIndex;
01865                     payload = MacCommandsBuffer;
01866                     framePort = 0;
01867                 }
01868             }
01869             MacCommandsInNextTx = false;
01870             // Store MAC commands which must be re-send in case the device does not receive a downlink anymore
01871             MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat );
01872             if( MacCommandsBufferToRepeatIndex > 0 )
01873             {
01874                 MacCommandsInNextTx = true;
01875             }
01876 
01877             if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
01878             {
01879                 Radio::radio.tx_buf[tx_buf_len++] = framePort;
01880 
01881                 if( framePort == 0 )
01882                 {
01883                     LoRaMacPayloadEncrypt ( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
01884                 }
01885                 else
01886                 {
01887                     LoRaMacPayloadEncrypt ( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] );
01888                 }
01889             }
01890             tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
01891 
01892             LoRaMacComputeMic( Radio::radio.tx_buf, tx_buf_len, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
01893 
01894             Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
01895             Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
01896             Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
01897             Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
01898 
01899             tx_buf_len += LORAMAC_MFR_LEN;
01900 
01901             break;
01902         case FRAME_TYPE_PROPRIETARY:
01903             if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
01904             {
01905                 memcpy1( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen );
01906                 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
01907             }
01908             break;
01909         default:
01910             return LORAMAC_STATUS_SERVICE_UNKNOWN;
01911     }
01912 
01913     return LORAMAC_STATUS_OK;
01914 }
01915 
01916 
01917 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
01918 {
01919     int8_t txPowerIndex = 0;
01920     int8_t txPower = 0;
01921 
01922     txPowerIndex = LoRaMacParams.ChannelsTxPower ;
01923     txPower = TxPowers[txPowerIndex];
01924     Radio::SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout );
01925 
01926     return LORAMAC_STATUS_OK;
01927 }
01928 
01929 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power )
01930 {
01931     Radio::SetTxContinuousWave( frequency, power, timeout );
01932 
01933     return LORAMAC_STATUS_OK;
01934 }
01935 
01936 void seconds()
01937 {
01938     mac_printf("second\r\n");
01939 }
01940 
01941 void on_dio0_top_half()
01942 {
01943 }
01944 
01945 unsigned get_symbol_period_us(uint8_t sf)
01946 {
01947     float bwMHz = LORA_BANDWIDTH_KHZ / 1000.0;
01948     // return symbol period in microseconds 
01949     return (1 << sf) / bwMHz;
01950 }
01951 
01952 const RadioEvents_t rev = {
01953     /* Dio0_top_half */     on_dio0_top_half,
01954     /* TxDone_topHalf */    OnRadioTxDone_topHalf,
01955     /* TxDone_botHalf */    OnRadioTxDone_bh,
01956     /* TxTimeout  */        OnRadioTxTimeout,
01957     /* RxDone  */           OnRadioRxDone,
01958     /* RxTimeout  */        OnRadioRxTimeout,
01959     /* RxError  */          OnRadioRxError,
01960     /* FhssChangeChannel  */NULL,
01961     /* CadDone  */          NULL
01962 };
01963 
01964 osThreadId_t tid_main;
01965 
01966 void sleep_test_callback()
01967 {
01968     txDoneAt = LowPowerClock::now();
01969     osThreadFlagsSet(tid_main, 1);
01970 }
01971 
01972 LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t  *primitives, LoRaMacCallback_t *callbacks )
01973 {
01974     if (primitives == NULL)
01975     {
01976         return LORAMAC_STATUS_PARAMETER_INVALID;
01977     }
01978 
01979     if( ( primitives->MacMcpsConfirm == NULL ) ||
01980         ( primitives->MacMcpsIndication == NULL ) ||
01981         ( primitives->MacMlmeConfirm == NULL ) )
01982     {
01983         return LORAMAC_STATUS_PARAMETER_INVALID;
01984     }
01985 
01986     LoRaMacPrimitives = primitives;
01987     LoRaMacCallbacks = callbacks;
01988 
01989     LoRaMacFlags.Value  = 0;
01990 
01991     JoinRequestTrials = 0;
01992     MaxJoinRequestTrials = 255;
01993 
01994     BeaconCtx.symbol_period_us = get_symbol_period_us(Datarates[LORAMAC_DEFAULT_DATARATE]);
01995 
01996     // Reset to defaults
01997     LoRaMacParamsDefaults.ChannelsTxPower  = LORAMAC_DEFAULT_TX_POWER;
01998     LoRaMacParamsDefaults.ChannelsDatarate_fixed  = LORAMAC_DEFAULT_DATARATE;
01999 
02000     LoRaMacParamsDefaults.SystemMaxRxError_ms  = 20;
02001     LoRaMacParamsDefaults.MinRxSymbols  = (LoRaMacParamsDefaults.SystemMaxRxError_ms  * 1000) / BeaconCtx.symbol_period_us; 
02002     if (LoRaMacParamsDefaults.MinRxSymbols  < MIN_SYMBOL_TIMEOUT)
02003         LoRaMacParamsDefaults.MinRxSymbols  = MIN_SYMBOL_TIMEOUT;
02004 
02005     LoRaMacParamsDefaults.MaxRxWindow  = MAX_RX_WINDOW;
02006 
02007     LoRaMacParamsDefaults.ReceiveDelay_us = RECEIVE_DELAY_us;
02008     LoRaMacParamsDefaults.JoinAcceptDelay_us = JOIN_ACCEPT_DELAY_us;
02009 
02010     LoRaMacParamsDefaults.ChannelsNbRep  = 1;
02011     LoRaMacParamsDefaults.Rx1DrOffset  = 0;
02012 
02013     for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
02014     {
02015         Channels[i].Frequency  = LORAMAC_FIRST_CHANNEL + (i * LORAMAC_STEPWIDTH_CHANNEL);
02016         Channels[i].DrRange .Value  = (LORAMAC_MAX_DATARATE << 4) | LORAMAC_MIN_DATARATE;
02017         Channels[i].Band  = 0;
02018     }
02019 
02020     // Init parameters which are not set in function ResetMacParameters
02021     LoRaMacParams.SystemMaxRxError_ms  = LoRaMacParamsDefaults.SystemMaxRxError_ms ;
02022     LoRaMacParams.MinRxSymbols  = LoRaMacParamsDefaults.MinRxSymbols ;
02023     LoRaMacParams.MaxRxWindow  = LoRaMacParamsDefaults.MaxRxWindow ;
02024     LoRaMacParams.ReceiveDelay_us = LoRaMacParamsDefaults.ReceiveDelay_us;
02025     LoRaMacParams.JoinAcceptDelay_us = LoRaMacParamsDefaults.JoinAcceptDelay_us;
02026     LoRaMacParams.ChannelsNbRep  = LoRaMacParamsDefaults.ChannelsNbRep ;
02027 
02028     ResetMacParameters( );
02029     if (LoRaMacCryptoInit() < 0) {
02030         return LORAMAC_STATUS_SERVICE_UNKNOWN;
02031     }
02032 
02033     // Initialize Radio driver
02034     Radio::Init(&rev);
02035 
02036     {
02037         unsigned sum = 0;
02038         sleep_manager_unlock_deep_sleep();
02039         tid_main = ThisThread::get_id();
02040         /*** How long this MCU takes to wake up from deep-sleep ***/
02041         for (unsigned n = 0; n < 16; n++) {
02042             long end, start;
02043             txDoneAt = LowPowerClock::now();
02044             start = txDoneAt.time_since_epoch().count();
02045 
02046             LoRaMacFlags.Value  = 0;
02047             rx_timeout.attach(sleep_test_callback, 10ms);
02048             ThisThread::flags_wait_any(1);
02049             end = LowPowerClock::now().time_since_epoch().count();
02050             sum += (end - start) - 10000;
02051         }
02052         LoRaMacFlags.Value  = 0;
02053         sum >>= 4;  // 16 samples = 2^4
02054         printf("mcu takes %uus to wake up\r\n", sum);
02055         mcu_wakeup_latency = microseconds(sum);
02056     }
02057 
02058     // Random seed initialization
02059     srand1( Radio::Random( ) );
02060 
02061     PublicNetwork = true;
02062     Radio::SetPublicNetwork( PublicNetwork );
02063     Radio::Sleep( );
02064 
02065     RxWindowsParam = ComputeRxWindowParameters(LORAMAC_DEFAULT_DATARATE, LoRaMacParams.SystemMaxRxError_ms );
02066 
02067     return LORAMAC_STATUS_OK;
02068 } // ..LoRaMacInitialization()
02069 
02070 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t * txInfo )
02071 {
02072     uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
02073 
02074     if( txInfo == NULL )
02075     {
02076         return LORAMAC_STATUS_PARAMETER_INVALID;
02077     }
02078 
02079     txInfo->CurrentPayloadSize  = LORAMAC_PHY_MAXPAYLOAD;
02080 
02081     if( txInfo->CurrentPayloadSize  >= fOptLen )
02082     {
02083         txInfo->MaxPossiblePayload  = txInfo->CurrentPayloadSize  - fOptLen;
02084     }
02085     else
02086     {
02087         return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
02088     }
02089 
02090     return LORAMAC_STATUS_OK;
02091 }
02092 
02093 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t  *mibGet )
02094 {
02095     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
02096 
02097     if( mibGet == NULL )
02098     {
02099         return LORAMAC_STATUS_PARAMETER_INVALID;
02100     }
02101 
02102     switch( mibGet->Type  )
02103     {
02104         case MIB_NETWORK_JOINED:
02105         {
02106             mibGet->Param .IsNetworkJoined  = LoRaMacFlags.Bits.IsLoRaMacNetworkJoined;
02107             break;
02108         }
02109         case MIB_NET_ID:
02110         {
02111             mibGet->Param .NetID  = LoRaMacNetID;
02112             break;
02113         }
02114         case MIB_DEV_ADDR:
02115         {
02116             mibGet->Param .DevAddr  = LoRaMacDevAddr;
02117             break;
02118         }
02119         case MIB_NWK_SKEY:
02120         {
02121             mibGet->Param .NwkSKey  = LoRaMacNwkSKey;
02122             break;
02123         }
02124         case MIB_APP_SKEY:
02125         {
02126             mibGet->Param .AppSKey  = LoRaMacAppSKey;
02127             break;
02128         }
02129         case MIB_PUBLIC_NETWORK:
02130         {
02131             mibGet->Param .EnablePublicNetwork  = PublicNetwork;
02132             break;
02133         }
02134         case MIB_CHANNELS_NB_REP:
02135         {
02136             mibGet->Param .ChannelNbRep  = LoRaMacParams.ChannelsNbRep ;
02137             break;
02138         }
02139         case MIB_MAX_RX_WINDOW_DURATION:
02140         {
02141             mibGet->Param .MaxRxWindow  = LoRaMacParams.MaxRxWindow ;
02142             break;
02143         }
02144         case MIB_CHANNELS_DEFAULT_TX_POWER:
02145         {
02146             mibGet->Param .ChannelsDefaultTxPower  = LoRaMacParamsDefaults.ChannelsTxPower ;
02147             break;
02148         }
02149         case MIB_CHANNELS_TX_POWER:
02150         {
02151             mibGet->Param .ChannelsTxPower  = LoRaMacParams.ChannelsTxPower ;
02152             break;
02153         }
02154         case MIB_UPLINK_COUNTER:
02155         {
02156             mibGet->Param .UpLinkCounter  = UpLinkCounter;
02157             break;
02158         }
02159         case MIB_DOWNLINK_COUNTER:
02160         {
02161             mibGet->Param .DownLinkCounter  = DownLinkCounter;
02162             break;
02163         }
02164         case MIB_MULTICAST_CHANNEL:
02165         {
02166             mibGet->Param .MulticastList  = MulticastChannels;
02167             break;
02168         }
02169         case MIB_SYSTEM_MAX_RX_ERROR:
02170         {
02171             mibGet->Param .SystemMaxRxError_ms  = LoRaMacParams.SystemMaxRxError_ms ;
02172             break;
02173         }
02174         case MIB_MIN_RX_SYMBOLS:
02175         {
02176             mibGet->Param .MinRxSymbols  = LoRaMacParams.MinRxSymbols ;
02177             break;
02178         }
02179         default:
02180             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
02181             break;
02182     }
02183 
02184     return status;
02185 }
02186 
02187 LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t  *mibSet )
02188 {
02189     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
02190 
02191     if( mibSet == NULL )
02192     {
02193         return LORAMAC_STATUS_PARAMETER_INVALID;
02194     }
02195 
02196     switch( mibSet->Type  )
02197     {
02198         case MIB_NETWORK_JOINED:
02199         {
02200             LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = mibSet->Param .IsNetworkJoined ;
02201             if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) {
02202                 mac_printf("beaconDetach\r\n");
02203                 BeaconCtx.timeout_rx.detach();
02204                 BeaconCtx.timeout_guard.detach();
02205                 BeaconCtx.state = BEACON_STATE_NONE;
02206             }
02207             break;
02208         }
02209         case MIB_NET_ID:
02210         {
02211             LoRaMacNetID = mibSet->Param .NetID ;
02212             break;
02213         }
02214         case MIB_DEV_ADDR:
02215         {
02216             LoRaMacDevAddr = mibSet->Param .DevAddr ;
02217             break;
02218         }
02219         case MIB_NWK_SKEY:
02220         {
02221             if( mibSet->Param .NwkSKey  != NULL )
02222             {
02223                 memcpy1( LoRaMacNwkSKey, mibSet->Param .NwkSKey ,
02224                                sizeof( LoRaMacNwkSKey ) );
02225             }
02226             else
02227             {
02228                 status = LORAMAC_STATUS_PARAMETER_INVALID;
02229             }
02230             break;
02231         }
02232         case MIB_APP_SKEY:
02233         {
02234             if( mibSet->Param .AppSKey  != NULL )
02235             {
02236                 memcpy1( LoRaMacAppSKey, mibSet->Param .AppSKey ,
02237                                sizeof( LoRaMacAppSKey ) );
02238             }
02239             else
02240             {
02241                 status = LORAMAC_STATUS_PARAMETER_INVALID;
02242             }
02243             break;
02244         }
02245         case MIB_PUBLIC_NETWORK:
02246         {
02247             PublicNetwork = mibSet->Param .EnablePublicNetwork ;
02248             Radio::SetPublicNetwork( PublicNetwork );
02249             break;
02250         }
02251         case MIB_CHANNELS_NB_REP:
02252         {
02253             if( ( mibSet->Param .ChannelNbRep  >= 1 ) &&
02254                 ( mibSet->Param .ChannelNbRep  <= 15 ) )
02255             {
02256                 LoRaMacParams.ChannelsNbRep  = mibSet->Param .ChannelNbRep ;
02257             }
02258             else
02259             {
02260                 status = LORAMAC_STATUS_PARAMETER_INVALID;
02261             }
02262             break;
02263         }
02264         case MIB_MAX_RX_WINDOW_DURATION:
02265         {
02266             LoRaMacParams.MaxRxWindow  = mibSet->Param .MaxRxWindow ;
02267             break;
02268         }
02269         case MIB_CHANNELS_DEFAULT_TX_POWER:
02270         {
02271             if( ValueInRange( mibSet->Param .ChannelsDefaultTxPower ,
02272                               LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
02273             {
02274                 LoRaMacParamsDefaults.ChannelsTxPower  = mibSet->Param .ChannelsDefaultTxPower ;
02275             }
02276             else
02277             {
02278                 status = LORAMAC_STATUS_PARAMETER_INVALID;
02279             }
02280             break;
02281         }
02282         case MIB_CHANNELS_TX_POWER:
02283         {
02284             if( ValueInRange( mibSet->Param .ChannelsTxPower ,
02285                               LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
02286             {
02287                 LoRaMacParams.ChannelsTxPower  = mibSet->Param .ChannelsTxPower ;
02288             }
02289             else
02290             {
02291                 status = LORAMAC_STATUS_PARAMETER_INVALID;
02292             }
02293             break;
02294         }
02295         case MIB_UPLINK_COUNTER:
02296         {
02297             UpLinkCounter = mibSet->Param .UpLinkCounter ;
02298             break;
02299         }
02300         case MIB_DOWNLINK_COUNTER:
02301         {
02302             DownLinkCounter = mibSet->Param .DownLinkCounter ;
02303             break;
02304         }
02305         case MIB_SYSTEM_MAX_RX_ERROR:
02306         {
02307             LoRaMacParams.SystemMaxRxError_ms  = LoRaMacParamsDefaults.SystemMaxRxError_ms  = mibSet->Param .SystemMaxRxError_ms ;
02308             break;
02309         }
02310         case MIB_MIN_RX_SYMBOLS:
02311         {
02312             LoRaMacParams.MinRxSymbols  = LoRaMacParamsDefaults.MinRxSymbols  = mibSet->Param .MinRxSymbols ;
02313             break;
02314         }
02315         default:
02316             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
02317             break;
02318     }
02319 
02320     return status;
02321 }
02322 
02323 LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t  *channelParam )
02324 {
02325     if( channelParam == NULL )
02326     {
02327         return LORAMAC_STATUS_PARAMETER_INVALID;
02328     }
02329 
02330     // Reset downlink counter
02331     channelParam->DownLinkCounter  = 0;
02332 
02333     if( MulticastChannels == NULL )
02334     {
02335         // New node is the fist element
02336         MulticastChannels = channelParam;
02337     }
02338     else
02339     {
02340         MulticastParams_t  *cur = MulticastChannels;
02341 
02342         // Search the last node in the list
02343         while( cur->Next  != NULL )
02344         {
02345             cur = cur->Next ;
02346         }
02347         // This function always finds the last node
02348         cur->Next  = channelParam;
02349     }
02350 
02351     return LORAMAC_STATUS_OK;
02352 }
02353 
02354 LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t  *channelParam )
02355 {
02356     if( channelParam == NULL )
02357     {
02358         return LORAMAC_STATUS_PARAMETER_INVALID;
02359     }
02360 
02361     if( MulticastChannels != NULL )
02362     {
02363         if( MulticastChannels == channelParam )
02364         {
02365           // First element
02366           MulticastChannels = channelParam->Next ;
02367         }
02368         else
02369         {
02370             MulticastParams_t  *cur = MulticastChannels;
02371 
02372             // Search the node in the list
02373             while( cur->Next  && cur->Next  != channelParam )
02374             {
02375                 cur = cur->Next ;
02376             }
02377             // If we found the node, remove it
02378             if( cur->Next  )
02379             {
02380                 cur->Next  = channelParam->Next ;
02381             }
02382         }
02383         channelParam->Next  = NULL;
02384     }
02385 
02386     return LORAMAC_STATUS_OK;
02387 }
02388 
02389 LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t  *mlmeRequest )
02390 {
02391     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
02392     LoRaMacHeader_t  macHdr;
02393 
02394     if( mlmeRequest == NULL )
02395     {
02396         return LORAMAC_STATUS_PARAMETER_INVALID;
02397     }
02398 
02399     memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
02400 
02401     MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ;
02402 
02403     switch( mlmeRequest->Type  )
02404     {
02405         case MLME_JOIN:
02406         {
02407             if( ( mlmeRequest->Req.Join .DevEui  == NULL ) ||
02408                 ( mlmeRequest->Req.Join .AppEui  == NULL ) ||
02409                 ( mlmeRequest->Req.Join .AppKey  == NULL ) ||
02410                 ( mlmeRequest->Req.Join .NbTrials  == 0 ) )
02411             {
02412                 return LORAMAC_STATUS_PARAMETER_INVALID;
02413             }
02414 
02415             // Enables at least the usage of all datarates.
02416             if( mlmeRequest->Req.Join .NbTrials  < 48 )
02417             {
02418                 mlmeRequest->Req.Join .NbTrials  = 48;
02419             }
02420 
02421             LoRaMacFlags.Bits.MlmeReq  = 1;
02422             MlmeConfirm.MlmeRequest = mlmeRequest->Type ;
02423 
02424             LoRaMacDevEui = mlmeRequest->Req.Join .DevEui ;
02425             LoRaMacAppEui = mlmeRequest->Req.Join .AppEui ;
02426             LoRaMacAppKey = mlmeRequest->Req.Join .AppKey ;
02427             MaxJoinRequestTrials = mlmeRequest->Req.Join .NbTrials ;
02428 
02429             // Reset variable JoinRequestTrials
02430             JoinRequestTrials = 0;
02431 
02432             // Setup header information
02433             macHdr.Value  = 0;
02434             macHdr.Bits.MType   = FRAME_TYPE_JOIN_REQ;
02435 
02436             ResetMacParameters( );
02437             LoRaMacFlags.Bits.expecting_beacon = false;
02438             BeaconCtx.state = BEACON_STATE_NONE;
02439 
02440             Channel = 0;    // start with first channel
02441             mac_printf("<ch0>");
02442             mac_printf("mlme-join-send ch%u\r\n", Channel);
02443             status = Send( &macHdr, 0, NULL, 0 );
02444             break;
02445         }
02446         case MLME_LINK_CHECK:
02447         {
02448             LoRaMacFlags.Bits.MlmeReq  = 1;
02449             // LoRaMac will send this command piggy-pack
02450             MlmeConfirm.MlmeRequest = mlmeRequest->Type ;
02451 
02452             status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
02453             break;
02454         }
02455         case MLME_TXCW:
02456         {
02457             MlmeConfirm.MlmeRequest = mlmeRequest->Type ;
02458             LoRaMacFlags.Bits.MlmeReq  = 1;
02459             status = SetTxContinuousWave( mlmeRequest->Req.TxCw .Timeout  );
02460             break;
02461         }
02462         case MLME_TXCW_1:
02463         {
02464             MlmeConfirm.MlmeRequest = mlmeRequest->Type ;
02465             LoRaMacFlags.Bits.MlmeReq  = 1;
02466             status = SetTxContinuousWave1( mlmeRequest->Req.TxCw .Timeout , mlmeRequest->Req.TxCw .Frequency , mlmeRequest->Req.TxCw .Power  );
02467             break;
02468         }
02469         default:
02470             break;
02471     }
02472 
02473     if( status != LORAMAC_STATUS_OK )
02474     {
02475         LoRaMacFlags.Bits.NodeAckRequested = false;
02476         LoRaMacFlags.Bits.MlmeReq  = 0;
02477     }
02478 
02479     return status;
02480 }
02481 
02482 LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t  *mcpsRequest )
02483 {
02484     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
02485     LoRaMacHeader_t  macHdr;
02486     uint8_t fPort = 0;
02487     void *fBuffer;
02488     uint16_t fBufferSize;
02489     bool readyToSend = false;
02490 
02491     if( mcpsRequest == NULL )
02492     {
02493         return LORAMAC_STATUS_PARAMETER_INVALID;
02494     }
02495 
02496     macHdr.Value  = 0;
02497     memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
02498     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ;
02499 
02500     switch( mcpsRequest->Type  )
02501     {
02502         case MCPS_UNCONFIRMED:
02503         {
02504             readyToSend = true;
02505 
02506             macHdr.Bits.MType  = FRAME_TYPE_DATA_UNCONFIRMED_UP;
02507             fPort = mcpsRequest->Req.Unconfirmed .fPort ;
02508             fBuffer = mcpsRequest->Req.Unconfirmed .fBuffer ;
02509             fBufferSize = mcpsRequest->Req.Unconfirmed .fBufferSize ;
02510             break;
02511         }
02512         case MCPS_CONFIRMED:
02513         {
02514             readyToSend = true;
02515 
02516             macHdr.Bits.MType  = FRAME_TYPE_DATA_CONFIRMED_UP;
02517             fPort = mcpsRequest->Req.Confirmed .fPort ;
02518             fBuffer = mcpsRequest->Req.Confirmed .fBuffer ;
02519             fBufferSize = mcpsRequest->Req.Confirmed .fBufferSize ;
02520             break;
02521         }
02522         case MCPS_PROPRIETARY:
02523         {
02524             readyToSend = true;
02525 
02526             macHdr.Bits.MType  = FRAME_TYPE_PROPRIETARY;
02527             fBuffer = mcpsRequest->Req.Proprietary .fBuffer ;
02528             fBufferSize = mcpsRequest->Req.Proprietary .fBufferSize ;
02529             break;
02530         }
02531         default:
02532             break;
02533     }
02534 
02535     if (readyToSend)
02536     {
02537         status = Send( &macHdr, fPort, fBuffer, fBufferSize );
02538         if (status == LORAMAC_STATUS_OK)
02539         {
02540             McpsConfirm.McpsRequest = mcpsRequest->Type ;
02541             LoRaMacFlags.Bits.McpsReq  = 1;
02542         }
02543         else
02544         {
02545             LoRaMacFlags.Bits.NodeAckRequested = false;
02546         }
02547     }
02548 
02549     return status;
02550 }
02551 
02552 void LoRaMacTestRxWindowsOn( bool enable )
02553 {
02554     IsRxWindowsEnabled = enable;
02555 }
02556 
02557 void LoRaMacTestSetMic( uint16_t txPacketCounter )
02558 {
02559     UpLinkCounter = txPacketCounter;
02560     //IsUpLinkCounterFixed = true;
02561 }
02562 
02563 void LoRaMacTestSetChannel( uint8_t channel )
02564 {
02565     mac_printf("set-testch%u\r\n", channel);
02566     Channel = channel;
02567 }
02568 
02569 
02570 static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError )
02571 {
02572     RxConfigParams_t rxConfigParams = { 0, 0 };
02573     double tSymbol = 0.0;
02574  
02575     rxConfigParams.Datarate = datarate;
02576  
02577 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
02578     if( datarate == DR_7 )
02579     { // FSK
02580         tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte
02581     }
02582     else
02583 #endif
02584     { // LoRa
02585         tSymbol = ( ( double )( 1 << Datarates[datarate] ) / LORA_BANDWIDTH_KHZ ) * 1e3;
02586     }
02587  
02588     rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols  - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols  ); // Computed number of symbols
02589     mac_printf("RxWindowTimeout:%lu\r\n", rxConfigParams.RxWindowTimeout);
02590  
02591     return rxConfigParams;
02592 }
02593 
02594 void LoRaMacBottomHalf()
02595 {
02596     if (LoRaMacFlags.Bits.join_send) {
02597         join_send_bh();
02598         LoRaMacFlags.Bits.join_send = 0;
02599     }
02600     if (LoRaMacFlags.Bits.send) {
02601         send_bh();
02602         LoRaMacFlags.Bits.send = 0;
02603     }
02604 
02605     if (LoRaMacFlags.Bits.reJoin) {
02606         MlmeReq_t  mlmeReq;
02607         mlmeReq.Type  = MLME_JOIN;
02608 
02609         mlmeReq.Req.Join .DevEui  = LoRaMacDevEui;
02610         mlmeReq.Req.Join .AppEui  = LoRaMacAppEui;
02611         mlmeReq.Req.Join .AppKey  = LoRaMacAppKey;
02612         mlmeReq.Req.Join .NbTrials  = 255;
02613 
02614         if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK)
02615             LoRaMacFlags.Bits.reJoin = 0;
02616     }
02617 
02618     Radio::service();
02619 }