From 6281073d8beab7bd479a02b1894428205828a06b Mon Sep 17 00:00:00 2001 From: Hasnain Virk Date: Mon, 11 Dec 2017 12:20:11 +0200 Subject: [PATCH] [IOTCELL-279] Using Application provided EventQueue The EventQueue thread in LoRaMac.cpp is disbanded and the LoRaWAN protocol is redesigned to store a pointer for an application provided EventQueue. It means that now the stack runs in the same thread as application. Application provided EventQueue is used to defer ISRs from radio driver and timer callbacks as well as the application events are queued to the same event loop. --- features/lorawan/LoRaWANInterface.cpp | 10 +- features/lorawan/LoRaWANInterface.h | 6 +- features/lorawan/LoRaWANStack.cpp | 37 ++--- features/lorawan/LoRaWANStack.h | 10 +- features/lorawan/lorastack/mac/LoRaMac.cpp | 133 ++++-------------- features/lorawan/lorastack/mac/LoRaMac.h | 9 +- features/lorawan/mbed_lib.json | 4 +- .../lorawan/system/lorawan_data_structures.h | 18 --- features/netsocket/LoRaWANBase.h | 5 +- 9 files changed, 82 insertions(+), 150 deletions(-) diff --git a/features/lorawan/LoRaWANInterface.cpp b/features/lorawan/LoRaWANInterface.cpp index e78ec41b60..92022a9c1d 100644 --- a/features/lorawan/LoRaWANInterface.cpp +++ b/features/lorawan/LoRaWANInterface.cpp @@ -21,6 +21,8 @@ #include "lorawan/LoRaWANInterface.h" +using namespace events; + inline LoRaWANStack& stk_obj() { return LoRaWANStack::get_lorawan_stack(); @@ -40,9 +42,13 @@ LoRaWANInterface::~LoRaWANInterface() { } -lora_mac_status_t LoRaWANInterface::initialize() +lora_mac_status_t LoRaWANInterface::initialize(EventQueue *queue) { - return stk_obj().initialize_mac_layer(); + if(!queue) { + return LORA_MAC_STATUS_PARAMETER_INVALID; + } + + return stk_obj().initialize_mac_layer(queue); } lora_mac_status_t LoRaWANInterface::connect() diff --git a/features/lorawan/LoRaWANInterface.h b/features/lorawan/LoRaWANInterface.h index 3f39f193c7..87d533da72 100644 --- a/features/lorawan/LoRaWANInterface.h +++ b/features/lorawan/LoRaWANInterface.h @@ -40,9 +40,11 @@ public: * * You must call this first to be able to use the LoRa stack. * - * \return 0 on success, a negative error code on failure. + * @param ev_queue A pointer to EventQueue provided by the application. + * + * @return 0 on success, a negative error code on failure. */ - virtual lora_mac_status_t initialize(); + virtual lora_mac_status_t initialize(events::EventQueue *ev_queue) ; /** Connect OTAA or ABP using Mbed-OS config system * diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index e9182491f0..c017eba21f 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -26,6 +26,7 @@ SPDX-License-Identifier: BSD-3-Clause #include #include #include "platform/Callback.h" +#include "events/EventQueue.h" #include "lorawan/LoRaWANStack.h" #if defined(FEATURE_COMMON_PAL) #include "mbed_trace.h" @@ -77,6 +78,7 @@ SPDX-License-Identifier: BSD-3-Clause #endif //MBED_CONF_LORA_PHY using namespace mbed; +using namespace events; /** * Helper function prototypes @@ -129,7 +131,7 @@ lora_mac_status_t LoRaWANStack::set_application_port(uint8_t port) ****************************************************************************/ LoRaWANStack::LoRaWANStack() : _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _mac_handlers(NULL), - _num_retry(1), _duty_cycle_on(LORAWAN_DUTYCYCLE_ON) + _num_retry(1), _queue(NULL), _duty_cycle_on(LORAWAN_DUTYCYCLE_ON) { #ifdef MBED_CONF_LORA_APP_PORT // is_port_valid() is not virtual, so we can call it in constructor @@ -173,7 +175,7 @@ radio_events_t *LoRaWANStack::bind_radio_driver(LoRaRadio& radio) lora_phy.set_radio_instance(radio); return _mac_handlers; } -lora_mac_status_t LoRaWANStack::initialize_mac_layer() +lora_mac_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) { if (DEVICE_STATE_NOT_INITIALIZED != _device_current_state) { @@ -188,6 +190,9 @@ lora_mac_status_t LoRaWANStack::initialize_mac_layer() tr_debug("Initializing MAC layer"); + //store a pointer to Event Queue + _queue = queue; + // Allocate memory for compliance test _compliance_test.app_data_buffer = compliance_test_buffer; @@ -196,7 +201,7 @@ lora_mac_status_t LoRaWANStack::initialize_mac_layer() LoRaMacPrimitives.MacMcpsIndication = callback(this, &LoRaWANStack::mcps_indication); LoRaMacPrimitives.MacMlmeConfirm = callback(this, &LoRaWANStack::mlme_confirm); LoRaMacCallbacks.TxNextPacketTimerEvent = callback(this, &LoRaWANStack::on_tx_next_packet_timer_event); - LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks, lora_phy); + LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks, &lora_phy, queue); mib_req.type = LORA_MIB_ADR; mib_req.param.adr_enable = LORAWAN_ADR_ON; @@ -394,7 +399,7 @@ void LoRaWANStack::on_tx_next_packet_timer_event(void) lora_mac_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) { - if (count > MAX_CONFIRMED_MSG_RETRIES) { + if (count >= MAX_CONFIRMED_MSG_RETRIES) { return LORA_MAC_STATUS_PARAMETER_INVALID; } @@ -1046,7 +1051,7 @@ void LoRaWANStack::mlme_confirm_handler(lora_mac_mlme_confirm_t *mlme_confirm) // Join attempt failed. set_device_state(DEVICE_STATE_IDLE); lora_state_machine(); - _events(JOIN_FAILURE); + _queue->call(_events, JOIN_FAILURE); } break; case LORA_MLME_LINK_CHECK: @@ -1127,14 +1132,14 @@ void LoRaWANStack::mcps_confirm_handler(lora_mac_mcps_confirm_t *mcps_confirm) // If sending timed out, we have a special event for that if (mcps_confirm->status == LORA_EVENT_INFO_STATUS_TX_TIMEOUT) { - _events(TX_TIMEOUT); + _queue->call(_events, TX_TIMEOUT); return; } if (mcps_confirm->status == LORA_EVENT_INFO_STATUS_RX2_TIMEOUT) { tr_debug("Did not receive Ack"); } // Otherwise send a general TX_ERROR event - _events(TX_ERROR); + _queue->call(_events, TX_ERROR); return; } @@ -1154,7 +1159,7 @@ void LoRaWANStack::mcps_confirm_handler(lora_mac_mcps_confirm_t *mcps_confirm) // data rate plus frame counter. _lw_session.uplink_counter = mcps_confirm->uplink_counter; _tx_msg.tx_ongoing = false; - _events(TX_DONE); + _queue->call(_events, TX_DONE); } /** MCPS-Indication event function @@ -1170,7 +1175,7 @@ void LoRaWANStack::mcps_indication_handler(lora_mac_mcps_indication_t *mcps_indi } if (mcps_indication->status != LORA_EVENT_INFO_STATUS_OK) { - _events(RX_ERROR); + _queue->call(_events, RX_ERROR); return; } @@ -1219,7 +1224,7 @@ void LoRaWANStack::mcps_indication_handler(lora_mac_mcps_indication_t *mcps_indi // This may never happen as both radio and MAC are limited // to the size 255 bytes tr_debug("Cannot receive more than buffer capacity!"); - _events(RX_ERROR); + _queue->call(_events, RX_ERROR); return; } else { _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; @@ -1233,7 +1238,7 @@ void LoRaWANStack::mcps_indication_handler(lora_mac_mcps_indication_t *mcps_indi // Notify application about received frame.. tr_debug("Received %d bytes", _rx_msg.rx_message.mcps_indication.buffer_size); _rx_msg.receive_ready = true; - _events(RX_DONE); + _queue->call(_events, RX_DONE); } else { // Invalid port, ports 0, 224 and 225-255 are reserved. } @@ -1800,7 +1805,7 @@ lora_mac_status_t LoRaWANStack::lora_state_machine() _lw_session.active = false; tr_debug("LoRaWAN protocol has been shut down."); - _events(DISCONNECTED); + _queue->call(_events, DISCONNECTED); status = LORA_MAC_STATUS_DEVICE_OFF; break; case DEVICE_STATE_NOT_INITIALIZED: @@ -1842,7 +1847,7 @@ lora_mac_status_t LoRaWANStack::lora_state_machine() // Session is now active _lw_session.active = true; // Tell the application that we are connected - _events(CONNECTED); + _queue->call(_events, CONNECTED); break; case DEVICE_STATE_ABP_CONNECTING: /* @@ -1874,7 +1879,7 @@ lora_mac_status_t LoRaWANStack::lora_state_machine() status = LORA_MAC_STATUS_OK; // Session is now active _lw_session.active = true; - _events(CONNECTED); + _queue->call(_events, CONNECTED); break; case DEVICE_STATE_SEND: // If a transmission is ongoing, don't interrupt @@ -1890,11 +1895,11 @@ lora_mac_status_t LoRaWANStack::lora_state_machine() break; case LORA_MAC_STATUS_CRYPTO_FAIL: tr_error("Crypto failed. Clearing TX buffers"); - _events(TX_CRYPTO_ERROR); + _queue->call(_events, TX_CRYPTO_ERROR); break; default: tr_error("Failure to schedule TX!"); - _events(TX_SCHEDULING_ERROR); + _queue->call(_events, TX_SCHEDULING_ERROR); break; } } diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index a4a5b62135..0e1aa7f675 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -27,6 +27,7 @@ SPDX-License-Identifier: BSD-3-Clause #define LORAWANSTACK_H_ #include +#include "events/EventQueue.h" #include "platform/Callback.h" #include "platform/NonCopyable.h" #include "lorawan/system/LoRaWANTimer.h" @@ -59,14 +60,14 @@ public: radio_events_t *bind_radio_driver(LoRaRadio& radio); /** End device initialization. - * - * \return 0 on success, a negative error code on failure. + * @param queue A pointer to an EventQueue passed from the application. + * @return LORA_MAC_STATUS_OK on success, a negative error code on failure. */ - lora_mac_status_t initialize_mac_layer(); + lora_mac_status_t initialize_mac_layer(events::EventQueue *queue); /** Sets all callbacks of the LoRaWAN interface. * - * \param *event_cb An event structure representing all possible callbacks. + * @param *event_cb An event structure representing all possible callbacks. */ void set_lora_event_cb(mbed::Callback event_cb); @@ -418,6 +419,7 @@ private: lora_mac_rx_message_t _rx_msg; uint8_t _app_port; uint8_t _num_retry; + events::EventQueue *_queue; bool _duty_cycle_on; }; diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 4d7418e24c..994945976d 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -38,12 +38,18 @@ SPDX-License-Identifier: BSD-3-Clause #define tr_error(...) (void(0)) //dummies if feature common pal is not added #endif //defined(FEATURE_COMMON_PAL) +using namespace events; /** * LoRa PHY layer object storage */ static LoRaPHY *lora_phy; +/** + * EventQueue object storage + */ +static EventQueue *ev_queue; + /** * Radio event callback handlers for MAC */ @@ -643,115 +649,49 @@ static void handle_delayed_tx_timer_event(void); static void handle_mac_state_check_timer_event(void); static void handle_next_tx_timer_event(void); -/*************************************************************************** - * LoRaMACTask class - Handles deferred callbacks * - * and timers from Interrupt context * - **************************************************************************/ -/** - * An internal class to facilitate MAC related tasks. - * Idea is to mould Semtech code as less as possible so - * as to make future integration smoother. - * - * This class is present only if RTOS is being used. - */ -#ifdef MBED_CONF_RTOS_PRESENT - -class LoRaMACTask { - -public: - LoRaMACTask(); - events::EventQueue queue; - -private: - rtos::Thread t; -}; - -LoRaMACTask::LoRaMACTask() - : queue(16 * EVENTS_EVENT_SIZE), - t(osPriorityNormal, 2048) -{ - t.start(callback(&queue, &events::EventQueue::dispatch_forever)); -} - -static LoRaMACTask mac_task; - -#endif //MBED_CONF_RTOS_PRESENT - /*************************************************************************** * ISRs - Handlers * **************************************************************************/ static void handle_tx_done(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRadioTxDone); -#else - OnRadioTxDone(); -#endif + ev_queue->call(OnRadioTxDone); } static void handle_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, - int8_t snr) + int8_t snr) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRadioRxDone, payload, size, rssi, snr); -#else - OnRadioRxDone(payload, size, rssi, snr); -#endif + ev_queue->call(OnRadioRxDone, payload, size, rssi, snr); } static void handle_rx_error(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRadioRxError); -#else - OnRadioRxError(); -#endif + ev_queue->call(OnRadioRxError); } static void handle_rx_timeout(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRadioRxTimeout); -#else - OnRadioRxTimeout(); -#endif + ev_queue->call(OnRadioRxTimeout); } static void handle_tx_timeout(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRadioTxTimeout); -#else - OnRadioTxTimeout(); -#endif + ev_queue->call(OnRadioTxTimeout); } static void handle_cad_done(bool cad) { -#ifdef MBED_CONF_RTOS_PRESENT - //mac_task.queue.call(OnRadioCadDone, cad); -#else - //TODO Doesn't exist yet - //OnRadioCadDOne(cad); -#endif + //TODO Not implemented yet + //ev_queue->call(OnRadioCadDone, cad); } static void handle_fhss_change_channel(uint8_t cur_channel) { -#ifdef MBED_CONF_RTOS_PRESENT - //mac_task.queue.call(OnRadioFHSSChangeChannel, cur_channel); -#else // TODO Not implemented yet - //OnRadioFHSSChangeChannel(cur_channel); -#endif + //ev_queue->call(OnRadioFHSSChangeChannel, cur_channel); } static void handle_mac_state_check_timer_event(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnMacStateCheckTimerEvent); -#else - OnMacStateCheckTimerEvent(); -#endif + ev_queue->call(OnMacStateCheckTimerEvent); } static void handle_next_tx_timer_event(void) @@ -760,47 +700,28 @@ static void handle_next_tx_timer_event(void) if ((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) { return; } -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnNextTx); -#else - OnNextTx(); -#endif + + ev_queue->call(OnNextTx); } static void handle_delayed_tx_timer_event(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnTxDelayedTimerEvent); -#else - OnTxDelayedTimerEvent(); -#endif + ev_queue->call(OnTxDelayedTimerEvent); } static void handle_ack_timeout() { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnAckTimeoutTimerEvent); -#else - OnAckTimeoutTimerEvent(); -#endif + ev_queue->call(OnAckTimeoutTimerEvent); } static void handle_rx1_timer_event(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRxWindow1TimerEvent); -#else - OnRxWindow1TimerEvent(); -#endif + ev_queue->call(OnRxWindow1TimerEvent); } static void handle_rx2_timer_event(void) { -#ifdef MBED_CONF_RTOS_PRESENT - mac_task.queue.call(OnRxWindow2TimerEvent); -#else - OnRxWindow2TimerEvent(); -#endif + ev_queue->call(OnRxWindow2TimerEvent); } /*************************************************************************** @@ -2552,17 +2473,23 @@ LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint return LORAMAC_STATUS_OK; } -LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaPHY& phy) +LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t *primitives, + LoRaMacCallback_t *callbacks, + LoRaPHY *phy, + EventQueue *queue) { GetPhyParams_t getPhy; PhyParam_t phyParam; + //store event queue pointer + ev_queue = queue; + if(!primitives || !callbacks) { return LORAMAC_STATUS_PARAMETER_INVALID; } - lora_phy = &phy; + lora_phy = phy; LoRaMacPrimitives = primitives; LoRaMacCallbacks = callbacks; diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 6981b68ae8..bb90661bc7 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -86,14 +86,19 @@ static const uint8_t LoRaMacMaxEirpTable[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21 * \param callbacks [in] - A pointer to the structure defining the LoRaMAC * callback functions. Refer to \ref LoRaMacCallback_t. * - * \param phy [in]- A reference to the selected PHY layer. + * \param phy [in]- A pointer to the selected PHY layer. + * + * \param queue [in]- A pointer to the application provided EventQueue. * * \retval `LoRaMacStatus_t` The status of the operation. The possible values are: * \ref LORAMAC_STATUS_OK * \ref LORAMAC_STATUS_PARAMETER_INVALID * \ref LORAMAC_STATUS_REGION_NOT_SUPPORTED. */ -LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaPHY& phy); +LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t *primitives, + LoRaMacCallback_t *callbacks, + LoRaPHY *phy, + events::EventQueue *queue); /*! * \brief Queries the LoRaMAC whether it is possible to send the next frame with diff --git a/features/lorawan/mbed_lib.json b/features/lorawan/mbed_lib.json index 63143cf56b..e4ddf214fa 100644 --- a/features/lorawan/mbed_lib.json +++ b/features/lorawan/mbed_lib.json @@ -71,8 +71,8 @@ "value": true }, "lbt-on": { - "help": "Enables/disables LBT. NOTE: Disable only for testing. Mandatory in many regions/sub-bands.", - "value": true + "help": "Enables/disables LBT. NOTE: [This feature is not yet integrated].", + "value": false } } } diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 437db4006b..a7ac9a8742 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1638,24 +1638,6 @@ typedef struct sLoRaMacCallback mbed::Callback TxNextPacketTimerEvent; }LoRaMacCallback_t; -/** - * The maximum size of receiver buffer. - */ -#ifdef MBED_CONF_LORA_RX_MESSAGE_BUFFER_MAX_SIZE -#define LORAWAN_RX_MESSAGE_BUFFER_MAX_SIZE MBED_CONF_LORA_RX_MESSAGE_BUFFER_MAX_SIZE -#else -#define LORAWAN_RX_MESSAGE_BUFFER_MAX_SIZE 5 -#endif - -/** - * The maximum size of transmission buffer. - */ -#ifdef MBED_CONF_LORA_TX_MESSAGE_BUFFER_MAX_SIZE -#define LORAWAN_TX_MESSAGE_BUFFER_MAX_SIZE MBED_CONF_LORA_TX_MESSAGE_BUFFER_MAX_SIZE -#else -#define LORAWAN_TX_MESSAGE_BUFFER_MAX_SIZE 5 -#endif - /** * The AES encryption/decryption cipher application session key. */ diff --git a/features/netsocket/LoRaWANBase.h b/features/netsocket/LoRaWANBase.h index b84c301215..f8826e09a2 100644 --- a/features/netsocket/LoRaWANBase.h +++ b/features/netsocket/LoRaWANBase.h @@ -20,6 +20,7 @@ #define LORAWAN_BASE_H_ #include "lorawan/system/lorawan_data_structures.h" +#include "events/EventQueue.h" class LoRaWANBase { @@ -28,10 +29,12 @@ public: * * You must call this before using the LoRa stack. * + * @param queue A pointer to EventQueue provided by the application. + * * @return LORA_MAC_STATUS_OK on success, a negative error code on * failure. */ - virtual lora_mac_status_t initialize() = 0; + virtual lora_mac_status_t initialize(events::EventQueue *queue) = 0; /** Connect OTAA or ABP by setup. *