[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.
pull/6087/head
Hasnain Virk 2017-12-11 12:20:11 +02:00 committed by Jimmy Brisson
parent 29353a8380
commit 6281073d8b
9 changed files with 82 additions and 150 deletions

View File

@ -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()

View File

@ -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
*

View File

@ -26,6 +26,7 @@ SPDX-License-Identifier: BSD-3-Clause
#include <string.h>
#include <stdlib.h>
#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;
}
}

View File

@ -27,6 +27,7 @@ SPDX-License-Identifier: BSD-3-Clause
#define LORAWANSTACK_H_
#include <stdint.h>
#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<void(lora_events_t)> 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;
};

View File

@ -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;

View File

@ -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

View File

@ -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
}
}
}

View File

@ -1638,24 +1638,6 @@ typedef struct sLoRaMacCallback
mbed::Callback<void()> 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.
*/

View File

@ -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.
*