takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaMac.h Source File

LoRaMac.h

Go to the documentation of this file.
00001 /**
00002  * \file      LoRaMac.h
00003  *
00004  * \brief     LoRa MAC layer implementation
00005  *
00006  * \copyright Revised BSD License, see LICENSE.TXT file include in the project
00007  *
00008  * \code
00009  *                ______                              _
00010  *               / _____)             _              | |
00011  *              ( (____  _____ ____ _| |_ _____  ____| |__
00012  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
00013  *               _____) ) ____| | | || |_| ____( (___| | | |
00014  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
00015  *              (C)2013 Semtech
00016  *
00017  *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
00018  *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
00019  *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
00020  *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
00021  *              embedded.connectivity.solutions===============
00022  *
00023  * \endcode
00024  *
00025  * \author    Miguel Luis ( Semtech )
00026  *
00027  * \author    Gregory Cristian ( Semtech )
00028  *
00029  * \author    Daniel Jaeckle ( STACKFORCE )
00030  *
00031  * \defgroup  LORAMAC LoRa MAC layer implementation
00032  *            This module specifies the API implementation of the LoRaMAC layer.
00033  *            This is a placeholder for a detailed description of the LoRaMac
00034  *            layer and the supported features.
00035  *
00036  * Copyright (c) 2017, Arm Limited and affiliates.
00037  * SPDX-License-Identifier: BSD-3-Clause
00038  *
00039  */
00040 #ifndef MBED_LORAWAN_MAC_H__
00041 #define MBED_LORAWAN_MAC_H__
00042 
00043 #include "events/EventQueue.h"
00044 
00045 #include "lorastack/phy/LoRaPHY.h"
00046 
00047 #include "system/LoRaWANTimer.h"
00048 #include "system/lorawan_data_structures.h"
00049 
00050 #include "LoRaMacChannelPlan.h"
00051 #include "LoRaMacCommand.h"
00052 #include "LoRaMacCrypto.h"
00053 #if MBED_CONF_RTOS_PRESENT
00054 #include "rtos/Mutex.h"
00055 #endif
00056 
00057 #include "platform/ScopedLock.h"
00058 
00059 class LoRaMac {
00060 
00061 public:
00062 
00063     /**
00064      * Constructor
00065      */
00066     LoRaMac();
00067 
00068     /**
00069      * Destructor
00070      */
00071     ~LoRaMac();
00072 
00073     /**
00074      * @brief   LoRaMAC layer initialization
00075      *
00076      * @details Initializes the LoRaMAC layer,
00077      *
00078      *
00079      * @param   queue [in]        A pointer to the application provided EventQueue.
00080      *
00081      * @param   scheduling_failure_handler    A callback to inform upper layer if a deferred
00082      *                                        transmission (after backoff or retry) fails to schedule.
00083      *
00084      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00085      *          \ref LORAWAN_STATUS_OK
00086      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00087      */
00088     lorawan_status_t initialize(events::EventQueue *queue,
00089                                 mbed::Callback<void(void)>scheduling_failure_handler);
00090 
00091     /**
00092      * @brief   Disconnect LoRaMac layer
00093      *
00094      * @details Cancels all outstanding requests and sets LoRaMac's
00095      *          internal state to idle.
00096      */
00097     void disconnect(void);
00098 
00099     /**
00100      * @brief nwk_joined Checks if device has joined to network
00101      * @return True if joined to network, false otherwise
00102      */
00103     bool nwk_joined();
00104 
00105     /**
00106      * @brief   Adds a channel plan to the system.
00107      *
00108      * @details Adds a whole channel plan or a single new channel if the plan
00109      *          contains only one channel and 'plan.nb_channels' is set to 1.
00110      *          Please note that this functionality is not available in all regions.
00111      *          Information on the allowed ranges is available at the
00112      *          LoRaWAN Regional Parameters V1.0.2rB.
00113      *
00114      * @param   plan [in]    A reference to application provided channel plan.
00115      *
00116      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00117      *          \ref LORAWAN_STATUS_OK
00118      *          \ref LORAWAN_STATUS_BUSY
00119      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00120      */
00121     lorawan_status_t add_channel_plan(const lorawan_channelplan_t &plan);
00122 
00123     /**
00124      * @brief   Removes a channel plan from the system.
00125      *
00126      * @details Removes the whole active channel plan except the 'Default Channels'.
00127      *          Please note that this functionality is not available in all regions.
00128      *          Information on the allowed ranges is available at the
00129      *          LoRaWAN Regional Parameters V1.0.2rB.
00130      *
00131      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00132      *          \ref LORAWAN_STATUS_OK
00133      *          \ref LORAWAN_STATUS_BUSY
00134      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00135      */
00136     lorawan_status_t remove_channel_plan();
00137 
00138     /**
00139      * @brief   Access active channel plan.
00140      *
00141      * @details Provides access to the current active channel plan.
00142      *
00143      * @param   plan [out]    A reference to application provided channel plan data
00144      *                        structure which will be filled in with active channel
00145      *                        plan.
00146      *
00147      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00148      *          \ref LORAWAN_STATUS_OK
00149      *          \ref LORAWAN_STATUS_BUSY
00150      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00151      */
00152     lorawan_status_t get_channel_plan(lorawan_channelplan_t &plan);
00153 
00154     /**
00155      * @brief   Remove a given channel from the active plan.
00156      *
00157      * @details Deactivates the given channel.
00158      *
00159      * @param id    Id of the channel.
00160      *
00161      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00162      *          \ref LORAWAN_STATUS_OK
00163      *          \ref LORAWAN_STATUS_BUSY
00164      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00165      */
00166     lorawan_status_t remove_single_channel(uint8_t id);
00167 
00168     /**
00169      * @brief   LoRaMAC multicast channel link service.
00170      *
00171      * @details Links a multicast channel into the linked list.
00172      *
00173      * @param [in] channel_param    The multicast channel parameters to link.
00174      *
00175      * @return  `lorawan_status_t` The  status of the operation. The possible values are:
00176      *          \ref LORAWAN_STATUS_OK
00177      *          \ref LORAWAN_STATUS_BUSY
00178      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00179      */
00180     lorawan_status_t multicast_channel_link(multicast_params_t  *channel_param);
00181 
00182     /**
00183      * @brief   LoRaMAC multicast channel unlink service.
00184      *
00185      * @details Unlinks a multicast channel from the linked list.
00186      *
00187      * @param [in] channel_param    The multicast channel parameters to unlink.
00188      *
00189      * @return  `lorawan_status_t` The status of the operation. The possible values are:
00190      *          \ref LORAWAN_STATUS_OK
00191      *          \ref LORAWAN_STATUS_BUSY
00192      *          \ref LORAWAN_STATUS_PARAMETER_INVALID
00193      */
00194     lorawan_status_t multicast_channel_unlink(multicast_params_t  *channel_param);
00195 
00196     /** Binds phy layer to MAC.
00197      *
00198      * @param phy   LoRaPHY object
00199      */
00200     void bind_phy(LoRaPHY &phy);
00201 
00202     /**
00203      * @brief Schedules the frame for sending.
00204      *
00205      * @details Prepares a full MAC frame and schedules it for physical
00206      *          transmission.
00207      *
00208      * @param [in] mac_hdr      MAC frame header field
00209      * @param [in] fport        Payload port
00210      * @param [in] fbuffer      MAC frame data buffer to be sent
00211      * @param [in] fbuffer_size MAC frame data buffer size
00212      *
00213      * @return status          Status of the operation. LORAWAN_STATUS_OK in case
00214      *                         of success and a negative error code in case of
00215      *                         failure.
00216      */
00217     lorawan_status_t send(loramac_mhdr_t  *mac_hdr, const uint8_t fport,
00218                           const void *fbuffer, uint16_t fbuffer_size);
00219 
00220     /**
00221      * @brief get_default_tx_datarate Gets the default TX datarate
00222      * @return default TX datarate.
00223      */
00224     uint8_t get_default_tx_datarate();
00225 
00226     /**
00227      * @brief enable_adaptive_datarate Enables or disables adaptive datarate.
00228      * @param adr_enabled Flag indicating is adr enabled or disabled.
00229      */
00230     void enable_adaptive_datarate(bool adr_enabled);
00231 
00232     /** Sets up the data rate.
00233      *
00234      * `set_datarate()` first verifies whether the data rate given is valid or not.
00235      * If it is valid, the system sets the given data rate to the channel.
00236      *
00237      * @param data_rate   The intended data rate, for example DR_0 or DR_1.
00238      *                    Note that the macro DR_* can mean different
00239      *                    things in different regions.
00240      *
00241      * @return            LORAWAN_STATUS_OK if everything goes well, otherwise
00242      *                    a negative error code.
00243      */
00244     lorawan_status_t set_channel_data_rate(uint8_t data_rate);
00245 
00246     /**
00247      * @brief tx_ongoing Check whether a prepare is done or not.
00248      * @return True if prepare_ongoing_tx is called, false otherwise.
00249      */
00250     bool tx_ongoing();
00251 
00252     /**
00253      * @brief set_tx_ongoing Changes the ongoing status for prepared message.
00254      * @param ongoing The value indicating the status.
00255      */
00256     void set_tx_ongoing(bool ongoing);
00257 
00258     /**
00259      * @brief reset_ongoing_tx Resets _ongoing_tx_msg.
00260      * @param reset_pending If true resets pending size also.
00261      */
00262     void reset_ongoing_tx(bool reset_pending = false);
00263 
00264     /**
00265      * @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg.
00266      * @param port                          The application port number.
00267      *
00268      * @param data                          A pointer to the data being sent. The ownership of the
00269      *                                      buffer is not transferred.
00270      *
00271      * @param length                        The size of data in bytes.
00272      *
00273      * @param flags                         A flag used to determine what type of
00274      *                                      message is being sent.
00275      *
00276      * @param num_retries                   Number of retries for a confirmed type message
00277      *
00278      * @return The number of bytes prepared for sending.
00279      */
00280     int16_t prepare_ongoing_tx(const uint8_t port, const uint8_t *data,
00281                                uint16_t length, uint8_t flags, uint8_t num_retries);
00282 
00283     /**
00284      * @brief send_ongoing_tx Sends the ongoing_tx_msg
00285      * @return LORAWAN_STATUS_OK or a negative error code on failure.
00286      */
00287     lorawan_status_t send_ongoing_tx(void);
00288 
00289     /**
00290      * @brief device_class Returns active device class
00291      * @return Device class in use.
00292      */
00293     device_class_t get_device_class() const;
00294 
00295     /**
00296      * @brief set_device_class Sets active device class.
00297      * @param device_class Device class to use.
00298      * @param ack_expiry_handler callback function to inform about ack expiry
00299      */
00300     void set_device_class(const device_class_t &device_class,
00301                           mbed::Callback<void(void)>ack_expiry_handler);
00302 
00303     /**
00304      * @brief setup_link_check_request Adds link check request command
00305      * to be put on next outgoing message (when it fits)
00306      */
00307     void setup_link_check_request();
00308 
00309     /**
00310      * @brief prepare_join prepares arguments to be ready for join() call.
00311      * @param params Join parameters to use, if NULL, the default will be used.
00312      * @param is_otaa True if joining is to be done using OTAA, false for ABP.
00313      *
00314      * @return LORAWAN_STATUS_OK or a negative error code on failure.
00315      */
00316     lorawan_status_t prepare_join(const lorawan_connect_t *params, bool is_otaa);
00317 
00318     /**
00319      * @brief join Joins the network.
00320      * @param is_otaa True if joining is to be done using OTAA, false for ABP.
00321      * @return LORAWAN_STATUS_OK or a negative error code on failure.
00322      */
00323     lorawan_status_t join(bool is_otaa);
00324 
00325     /**
00326      * MAC operations upon successful transmission
00327      */
00328     void on_radio_tx_done(lorawan_time_t timestamp);
00329 
00330     /**
00331      * MAC operations upon reception
00332      */
00333     void on_radio_rx_done(const uint8_t *const payload, uint16_t size,
00334                           int16_t rssi, int8_t snr);
00335 
00336     /**
00337      * MAC operations upon transmission timeout
00338      */
00339     void on_radio_tx_timeout(void);
00340 
00341     /**
00342      * MAC operations upon empty reception slots
00343      *
00344      * @param is_timeout false when radio encountered an error
00345      *                   true when the an RX slot went empty
00346      *
00347      * @return current RX slot
00348      */
00349     void on_radio_rx_timeout(bool is_timeout);
00350 
00351     /**
00352      * Handles retransmissions of Join requests if an Accept
00353      * was not received.
00354      *
00355      * @returns true if a retry will be made
00356      */
00357     bool continue_joining_process(void);
00358 
00359     /**
00360      * Checks if the CONFIRMED data can be sent again or not.
00361      */
00362     bool continue_sending_process(void);
00363 
00364     /**
00365      * Read-only access to MAC primitive blocks
00366      */
00367     const loramac_mcps_confirm_t  *get_mcps_confirmation() const;
00368     const loramac_mcps_indication_t  *get_mcps_indication() const;
00369     const loramac_mlme_confirm_t  *get_mlme_confirmation() const;
00370     const loramac_mlme_indication_t  *get_mlme_indication() const;
00371 
00372     /**
00373      * Post processing steps in response to actions carried out
00374      * by controller layer and Mac
00375      */
00376     void post_process_mcps_req(void);
00377     void post_process_mcps_ind(void);
00378     void post_process_mlme_request(void);
00379     void post_process_mlme_ind(void);
00380 
00381     /**
00382      * Set battery level query callback
00383      */
00384     void set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level);
00385 
00386     /**
00387      * Returns the event ID of backoff timer.
00388      */
00389     int get_backoff_timer_event_id(void);
00390 
00391     /**
00392      * Clears out the TX pipe by discarding any outgoing message if the backoff
00393      * timer is still running.
00394      */
00395     lorawan_status_t clear_tx_pipe(void);
00396 
00397     /**
00398      * Gets the current time
00399      */
00400     lorawan_time_t get_current_time(void);
00401 
00402     /**
00403      * Gets the current receive slot
00404      */
00405     rx_slot_t  get_current_slot(void);
00406 
00407     /**
00408      * These locks trample through to the upper layers and make
00409      * the stack thread safe.
00410      */
00411 #if MBED_CONF_RTOS_PRESENT
00412     void lock(void)
00413     {
00414         _mutex.lock();
00415     }
00416     void unlock(void)
00417     {
00418         _mutex.unlock();
00419     }
00420 #else
00421     void lock(void) { }
00422     void unlock(void) { }
00423 #endif
00424 
00425 private:
00426     /**
00427      * @brief   Queries the LoRaMAC the maximum possible FRMPayload size to send.
00428      *          The LoRaMAC takes the scheduled MAC commands into account and returns
00429      *          corresponding value.
00430      *
00431      * @param   fopts_len     [in]    Number of mac commands in the queue pending.
00432      *
00433      * @return  Size of the biggest packet that can be sent.
00434      *          Please note that if the size of the MAC commands in the queue do
00435      *          not fit into the payload size on the related datarate, the LoRaMAC will
00436      *          omit the MAC commands.
00437      */
00438     uint8_t get_max_possible_tx_size(uint8_t fopts_len);
00439 
00440     /**
00441      * @brief set_nwk_joined This is used for ABP mode for which real joining does not happen
00442      * @param joined True if device has joined in network, false otherwise
00443      */
00444     void set_nwk_joined(bool joined);
00445 
00446     /**
00447      * @brief Configures the events to trigger an MLME-Indication with
00448      *        a MLME type of MLME_SCHEDULE_UPLINK.
00449      */
00450     void set_mlme_schedule_ul_indication(void);
00451 
00452     /**
00453      * @brief Resets MAC specific parameters to default
00454      */
00455     void reset_mac_parameters(void);
00456 
00457     /**
00458      * Handles a Join Accept frame
00459      */
00460     void handle_join_accept_frame(const uint8_t *payload, uint16_t size);
00461 
00462     /**
00463      * Handles data frames
00464      */
00465     void handle_data_frame(const uint8_t *payload,  uint16_t size, uint8_t ptr_pos,
00466                            uint8_t msg_type, int16_t rssi, int8_t snr);
00467 
00468     /**
00469      * Send a Join Request
00470      */
00471     lorawan_status_t send_join_request();
00472 
00473     /**
00474      * Handles retransmissions
00475      */
00476     lorawan_status_t handle_retransmission();
00477 
00478     /**
00479      * Checks if the frame is valid
00480      */
00481     void check_frame_size(uint16_t size);
00482 
00483     /**
00484      * Performs MIC
00485      */
00486     bool message_integrity_check(const uint8_t *payload, uint16_t size,
00487                                  uint8_t *ptr_pos, uint32_t address,
00488                                  uint32_t *downlink_counter, const uint8_t *nwk_skey);
00489 
00490     /**
00491      * Decrypts and extracts data and MAC commands from the received encrypted
00492      * payload
00493      */
00494     void extract_data_and_mac_commands(const uint8_t *payload, uint16_t size,
00495                                        uint8_t fopts_len, uint8_t *nwk_skey,
00496                                        uint8_t *app_skey, uint32_t address,
00497                                        uint32_t downlink_frame_counter,
00498                                        int16_t rssi, int8_t snr);
00499     /**
00500      * Decrypts and extracts MAC commands from the received encrypted
00501      * payload if there is no data
00502      */
00503     void extract_mac_commands_only(const uint8_t *payload, int8_t snr, uint8_t fopts_len);
00504 
00505     /**
00506      * Callback function to be executed when the DC backoff timer expires
00507      */
00508     void on_backoff_timer_expiry(void);
00509 
00510     /**
00511      * At the end of an RX1 window timer, an RX1 window is opened using this method.
00512      */
00513     void open_rx1_window(void);
00514 
00515     /**
00516      * At the end of an RX2 window timer, an RX2 window is opened using this method.
00517      */
00518     void open_rx2_window(void);
00519 
00520     /**
00521      * A method to retry a CONFIRMED message after a particular time period
00522      * (ACK_TIMEOUT = TIME_IN_MS) if the ack was not received
00523      */
00524     void on_ack_timeout_timer_event(void);
00525 
00526     /*!
00527      * \brief Check if the OnAckTimeoutTimer has do be disabled. If so, the
00528      *        function disables it.
00529      *
00530      * \param [in] node_ack_requested Set to true, if the node has requested an ACK
00531      * \param [in] dev_class The device class
00532      * \param [in] ack_received Set to true, if the node has received an ACK
00533      * \param [in] ack_timeout_retries_counter Retries counter for confirmed uplinks
00534      * \param [in] ack_timeout_retries Maximum retries for confirmed uplinks
00535      */
00536     void check_to_disable_ack_timeout(bool node_ack_requested,
00537                                       device_class_t dev_class,
00538                                       bool ack_received,
00539                                       uint8_t ack_timeout_retries_counter,
00540                                       uint8_t ack_timeout_retries);
00541 
00542     /**
00543      * Validates if the payload fits into the frame, taking the datarate
00544      * into account.
00545      *
00546      * Please Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0.2
00547      */
00548     bool validate_payload_length(uint16_t length, int8_t datarate, uint8_t fopts_len);
00549 
00550     /**
00551      * Prepares MAC frame on the behest of send() API.
00552      */
00553     lorawan_status_t prepare_frame(loramac_mhdr_t  *mac_hdr,
00554                                    loramac_frame_ctrl_t  *fctrl, const uint8_t fport,
00555                                    const void *fbuffer, uint16_t fbuffer_size);
00556 
00557     /**
00558      * Schedules a transmission on the behest of send() API.
00559      */
00560     lorawan_status_t schedule_tx();
00561 
00562     /**
00563      * Calculates the back-off time for the band of a channel.
00564      * Takes in the last used channel id as a parameter.
00565      */
00566     void calculate_backOff(uint8_t channel_id);
00567 
00568     /**
00569      * Hands over the MAC frame to PHY layer.
00570      */
00571     lorawan_status_t send_frame_on_channel(uint8_t channel);
00572 
00573     /**
00574      * Resets MAC primitive blocks
00575      */
00576     void reset_mcps_confirmation(void);
00577     void reset_mlme_confirmation(void);
00578     void reset_mcps_indication(void);
00579 
00580     /**
00581      * @brief set_tx_continuous_wave Puts the system in continuous transmission mode
00582      * @param [in] channel A Channel to use
00583      * @param [in] datarate A datarate to use
00584      * @param [in] tx_power A RF output power to use
00585      * @param [in] max_eirp A maximum possible EIRP to use
00586      * @param [in] antenna_gain Antenna gain to use
00587      * @param [in] timeout Time in seconds while the radio is kept in continuous wave mode
00588      */
00589     void set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power,
00590                                 float max_eirp, float antenna_gain, uint16_t timeout);
00591 
00592 private:
00593     typedef mbed::ScopedLock<LoRaMac> Lock;
00594 #if MBED_CONF_RTOS_PRESENT
00595     rtos::Mutex _mutex;
00596 #endif
00597 
00598     /**
00599      * Timer subsystem handle
00600      */
00601     LoRaWANTimeHandler _lora_time;
00602 
00603     /**
00604      * LoRa PHY layer object storage
00605      */
00606     LoRaPHY *_lora_phy;
00607 
00608     /**
00609      * MAC command handle
00610      */
00611     LoRaMacCommand _mac_commands;
00612 
00613     /**
00614      * Channel planning subsystem
00615      */
00616     LoRaMacChannelPlan _channel_plan;
00617 
00618     /**
00619      * Crypto handling subsystem
00620      */
00621     LoRaMacCrypto _lora_crypto;
00622 
00623     /**
00624      * Central MAC layer data storage
00625      */
00626     loramac_protocol_params _params;
00627 
00628     /**
00629      * EventQueue object storage
00630      */
00631     events::EventQueue *_ev_queue;
00632 
00633     /**
00634      * Class C doesn't timeout in RX2 window as it is a continuous window.
00635      * We use this callback to inform the LoRaWANStack controller that the
00636      * system cannot do more retries.
00637      */
00638     mbed::Callback<void(void)> _ack_expiry_handler_for_class_c;
00639 
00640     /**
00641      * Transmission is async, i.e., a call to schedule_tx() may be deferred to
00642      * a time after a certain back off. We use this callback to inform the
00643      * controller layer that a specific TX transaction failed to schedule after
00644      * backoff or retry.
00645      */
00646     mbed::Callback<void(void)> _scheduling_failure_handler;
00647 
00648     /**
00649      * Structure to hold MCPS indication data.
00650      */
00651     loramac_mcps_indication_t  _mcps_indication;
00652 
00653     /**
00654      * Structure to hold MCPS confirm data.
00655      */
00656     loramac_mcps_confirm_t  _mcps_confirmation;
00657 
00658     /**
00659      * Structure to hold MLME indication data.
00660      */
00661     loramac_mlme_indication_t  _mlme_indication;
00662 
00663     /**
00664      * Structure to hold MLME confirm data.
00665      */
00666     loramac_mlme_confirm_t  _mlme_confirmation;
00667 
00668     loramac_tx_message_t _ongoing_tx_msg;
00669 
00670     bool _is_nwk_joined;
00671 
00672     bool _continuous_rx2_window_open;
00673 
00674     device_class_t _device_class;
00675 };
00676 
00677 #endif // MBED_LORAWAN_MAC_H__