Merge pull request #6628 from kivaisan/mlme_indication_and_auto_uplink_config

Lora: Make automatic uplink message configurable
pull/6686/head
Martin Kojtal 2018-04-19 17:25:33 +02:00 committed by GitHub
commit 13913c7301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 91 deletions

View File

@ -58,19 +58,19 @@ using namespace events;
/*****************************************************************************
* Private Member Functions *
****************************************************************************/
bool LoRaWANStack::is_port_valid(uint8_t port)
bool LoRaWANStack::is_port_valid(uint8_t port, bool allow_port_0)
{
//Application should not use reserved and illegal port numbers.
if (port >= 224 || port == 0) {
return false;
if (port == 0) {
return allow_port_0;
} else {
return true;
}
}
lorawan_status_t LoRaWANStack::set_application_port(uint8_t port)
lorawan_status_t LoRaWANStack::set_application_port(uint8_t port, bool allow_port_0)
{
if (is_port_valid(port)) {
if (is_port_valid(port, allow_port_0)) {
_app_port = port;
return LORAWAN_STATUS_OK;
}
@ -236,10 +236,14 @@ void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t *mlmeIndica
switch( mlmeIndication->indication_type )
{
case MLME_SCHEDULE_UPLINK:
{// The MAC signals that we shall provide an uplink as soon as possible
// TODO: Sending implementation missing and will be implemented using
// another task.
//OnTxNextPacketTimerEvent( );
{
// The MAC signals that we shall provide an uplink as soon as possible
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands...");
send_automatic_uplink_message(0);
#else
send_event_to_application(UPLINK_REQUIRED);
#endif
break;
}
default:
@ -332,8 +336,26 @@ lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
return _loramac.set_channel_data_rate(data_rate);
}
void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const
{
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, event);
MBED_ASSERT(ret != 0);
(void)ret;
}
}
void LoRaWANStack::send_automatic_uplink_message(const uint8_t port)
{
const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true);
if (ret < 0) {
send_event_to_application(AUTOMATIC_UPLINK_ERROR);
}
}
int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags, bool null_allowed)
uint16_t length, uint8_t flags,
bool null_allowed, bool allow_port_0)
{
if (!null_allowed && !data) {
return LORAWAN_STATUS_PARAMETER_INVALID;
@ -364,7 +386,7 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
return LORAWAN_STATUS_NO_NETWORK_JOINED;
}
status = set_application_port(port);
status = set_application_port(port, allow_port_0);
if (status != LORAWAN_STATUS_OK) {
tr_error("Illegal application port definition.");
@ -379,7 +401,6 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
status = lora_state_machine(DEVICE_STATE_SEND);
// send user the length of data which is scheduled now.
@ -501,11 +522,7 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm)
tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
}
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(JOIN_FAILURE);
}
break;
case MLME_LINK_CHECK:
@ -541,21 +558,13 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status);
if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) {
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(TX_TIMEOUT);
return;
} else if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) {
tr_debug("Did not receive Ack");
}
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(TX_ERROR);
return;
}
@ -566,22 +575,14 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
_lw_session.uplink_counter = mcps_confirm->ul_frame_counter;
_loramac.set_tx_ongoing(false);
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_DONE);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(TX_DONE);
}
void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication)
{
if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) {
if (_callbacks.events) {
tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status);
const int ret = _queue->call(_callbacks.events, RX_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status);
send_event_to_application(RX_ERROR);
return;
}
@ -645,32 +646,28 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic
tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
_rx_msg.receive_ready = true;
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, RX_DONE);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(RX_DONE);
//TODO: below if clauses can be combined,
// because those are calling same function with same parameters
// If fPending bit is set we try to generate an empty packet
// with CONFIRMED flag set. We always set a CONFIRMED flag so
// that we could retry a certain number of times if the uplink
// failed for some reason
if (_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) {
tr_debug("Pending bit set. Sending empty message to receive pending data...");
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
}
// Class C and node received a confirmed message so we need to
// send an empty packet to acknowledge the message.
// This scenario is unspecified by LoRaWAN 1.0.2 specification,
// but version 1.1.0 says that network SHALL not send any new
// confirmed messages until ack has been sent
if (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) {
tr_debug("Acknowledging confirmed message (class C)...");
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
/*
* If fPending bit is set we try to generate an empty packet
* with CONFIRMED flag set. We always set a CONFIRMED flag so
* that we could retry a certain number of times if the uplink
* failed for some reason
* or
* Class C and node received a confirmed message so we need to
* send an empty packet to acknowledge the message.
* This scenario is unspecified by LoRaWAN 1.0.2 specification,
* but version 1.1.0 says that network SHALL not send any new
* confirmed messages until ack has been sent
*/
if ((_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) ||
(_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED)) {
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
tr_debug("Sending empty uplink message...");
send_automatic_uplink_message(mcps_indication->port);
#else
send_event_to_application(UPLINK_REQUIRED);
#endif
}
} else {
// Invalid port, ports 0, 224 and 225-255 are reserved.
@ -741,11 +738,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
_lw_session.active = false;
tr_debug("LoRaWAN protocol has been shut down.");
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, DISCONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(DISCONNECTED);
status = LORAWAN_STATUS_DEVICE_OFF;
break;
case DEVICE_STATE_NOT_INITIALIZED:
@ -773,11 +766,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
_lw_session.active = true;
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, CONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(CONNECTED);
status = LORAWAN_STATUS_OK;
break;
case DEVICE_STATE_ABP_CONNECTING:
@ -789,11 +778,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
status = LORAWAN_STATUS_OK;
_lw_session.active = true;
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, CONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(CONNECTED);
break;
case DEVICE_STATE_SEND:
if (_loramac.tx_ongoing()) {
@ -808,19 +793,11 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
break;
case LORAWAN_STATUS_CRYPTO_FAIL:
tr_error("Crypto failed. Clearing TX buffers");
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(TX_CRYPTO_ERROR);
break;
default:
tr_error("Failure to schedule TX!");
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
send_event_to_application(TX_SCHEDULING_ERROR);
break;
}
}

View File

@ -291,12 +291,15 @@ public:
* @param null_allowed Internal use only. Needed for sending empty packet
* having CONFIRMED bit on.
*
* @param allow_port_0 Internal use only. Needed for flushing MAC commands.
*
* @return The number of bytes sent, or
* LORAWAN_STATUS_WOULD_BLOCK if another TX is
* ongoing, or a negative error code on failure.
*/
int16_t handle_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags, bool null_allowed = false);
uint16_t length, uint8_t flags,
bool null_allowed = false, bool allow_port_0 = false);
/** Receives a message from the Network Server.
*
@ -399,7 +402,7 @@ private:
/**
* Checks if the user provided port is valid or not
*/
bool is_port_valid(uint8_t port);
bool is_port_valid(uint8_t port, bool allow_port_0 = false);
/**
* State machine for stack controller layer.
@ -439,13 +442,28 @@ private:
/**
* Sets up user application port
*/
lorawan_status_t set_application_port(uint8_t port);
lorawan_status_t set_application_port(uint8_t port, bool allow_port_0 = false);
/**
* Handles connection internally
*/
lorawan_status_t handle_connect(bool is_otaa);
/** Send event to application.
*
* @param event The event to be sent.
*/
void send_event_to_application(const lorawan_event_t event) const;
/** Send empty uplink message to network.
*
* Sends an empty confirmed message to gateway.
*
* @param port The event to be sent.
*/
void send_automatic_uplink_message(const uint8_t port);
private:
LoRaMac _loramac;

View File

@ -185,6 +185,10 @@ typedef struct lorawan_connect {
* RX_TIMEOUT, - Not yet mapped
* RX_ERROR - A general RX error
* JOIN_FAILURE - When all Joining retries are exhausted
* UPLINK_REQUIRED - Stack indicates application that some uplink needed
* AUTOMATIC_UPLINK_ERROR - Stack tried automatically send uplink but some error occurred.
* Application should initiate uplink as soon as possible.
*
*/
typedef enum lora_events {
CONNECTED=0,
@ -198,6 +202,8 @@ typedef enum lora_events {
RX_TIMEOUT,
RX_ERROR,
JOIN_FAILURE,
UPLINK_REQUIRED,
AUTOMATIC_UPLINK_ERROR,
} lorawan_event_t;
/**

View File

@ -60,6 +60,10 @@
"lbt-on": {
"help": "Enables/disables LBT. NOTE: [This feature is not yet integrated].",
"value": false
},
"automatic-uplink-message": {
"help": "Stack will automatically send an uplink message when lora server requires immediate response",
"value": true
}
}
}