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 * * 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. //Application should not use reserved and illegal port numbers.
if (port >= 224 || port == 0) { if (port == 0) {
return false; return allow_port_0;
} else { } else {
return true; 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; _app_port = port;
return LORAWAN_STATUS_OK; return LORAWAN_STATUS_OK;
} }
@ -236,10 +236,14 @@ void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t *mlmeIndica
switch( mlmeIndication->indication_type ) switch( mlmeIndication->indication_type )
{ {
case MLME_SCHEDULE_UPLINK: 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 // The MAC signals that we shall provide an uplink as soon as possible
// another task. #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
//OnTxNextPacketTimerEvent( ); 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; break;
} }
default: 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); 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, 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) { if (!null_allowed && !data) {
return LORAWAN_STATUS_PARAMETER_INVALID; 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; return LORAWAN_STATUS_NO_NETWORK_JOINED;
} }
status = set_application_port(port); status = set_application_port(port, allow_port_0);
if (status != LORAWAN_STATUS_OK) { if (status != LORAWAN_STATUS_OK) {
tr_error("Illegal application port definition."); 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); int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
status = lora_state_machine(DEVICE_STATE_SEND); status = lora_state_machine(DEVICE_STATE_SEND);
// send user the length of data which is scheduled now. // 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 !"); tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
} }
if (_callbacks.events) { send_event_to_application(JOIN_FAILURE);
const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
MBED_ASSERT(ret != 0);
(void)ret;
}
} }
break; break;
case MLME_LINK_CHECK: 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); tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status);
if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) { if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) {
if (_callbacks.events) { send_event_to_application(TX_TIMEOUT);
const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
MBED_ASSERT(ret != 0);
(void)ret;
}
return; return;
} else if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) { } else if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) {
tr_debug("Did not receive Ack"); tr_debug("Did not receive Ack");
} }
if (_callbacks.events) { send_event_to_application(TX_ERROR);
const int ret = _queue->call(_callbacks.events, TX_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
return; 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; _lw_session.uplink_counter = mcps_confirm->ul_frame_counter;
_loramac.set_tx_ongoing(false); _loramac.set_tx_ongoing(false);
if (_callbacks.events) { send_event_to_application(TX_DONE);
const int ret = _queue->call(_callbacks.events, TX_DONE);
MBED_ASSERT(ret != 0);
(void)ret;
}
} }
void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication) void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication)
{ {
if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) { if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) {
if (_callbacks.events) {
tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status); tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status);
const int ret = _queue->call(_callbacks.events, RX_ERROR); send_event_to_application(RX_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
return; 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); tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
_rx_msg.receive_ready = true; _rx_msg.receive_ready = true;
if (_callbacks.events) { send_event_to_application(RX_DONE);
const int ret = _queue->call(_callbacks.events, RX_DONE);
MBED_ASSERT(ret != 0);
(void)ret;
}
//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
// If fPending bit is set we try to generate an empty packet * that we could retry a certain number of times if the uplink
// with CONFIRMED flag set. We always set a CONFIRMED flag so * failed for some reason
// that we could retry a certain number of times if the uplink * or
// failed for some reason * Class C and node received a confirmed message so we need to
if (_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) { * send an empty packet to acknowledge the message.
tr_debug("Pending bit set. Sending empty message to receive pending data..."); * This scenario is unspecified by LoRaWAN 1.0.2 specification,
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); * but version 1.1.0 says that network SHALL not send any new
} * confirmed messages until ack has been sent
*/
// Class C and node received a confirmed message so we need to if ((_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) ||
// send an empty packet to acknowledge the message. (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED)) {
// This scenario is unspecified by LoRaWAN 1.0.2 specification, #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
// but version 1.1.0 says that network SHALL not send any new tr_debug("Sending empty uplink message...");
// confirmed messages until ack has been sent send_automatic_uplink_message(mcps_indication->port);
if (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { #else
tr_debug("Acknowledging confirmed message (class C)..."); send_event_to_application(UPLINK_REQUIRED);
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); #endif
} }
} else { } else {
// Invalid port, ports 0, 224 and 225-255 are reserved. // 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; _lw_session.active = false;
tr_debug("LoRaWAN protocol has been shut down."); tr_debug("LoRaWAN protocol has been shut down.");
if (_callbacks.events) { send_event_to_application(DISCONNECTED);
const int ret = _queue->call(_callbacks.events, DISCONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
status = LORAWAN_STATUS_DEVICE_OFF; status = LORAWAN_STATUS_DEVICE_OFF;
break; break;
case DEVICE_STATE_NOT_INITIALIZED: 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; _lw_session.active = true;
if (_callbacks.events) { send_event_to_application(CONNECTED);
const int ret = _queue->call(_callbacks.events, CONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
status = LORAWAN_STATUS_OK; status = LORAWAN_STATUS_OK;
break; break;
case DEVICE_STATE_ABP_CONNECTING: 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; status = LORAWAN_STATUS_OK;
_lw_session.active = true; _lw_session.active = true;
if (_callbacks.events) { send_event_to_application(CONNECTED);
const int ret = _queue->call(_callbacks.events, CONNECTED);
MBED_ASSERT(ret != 0);
(void)ret;
}
break; break;
case DEVICE_STATE_SEND: case DEVICE_STATE_SEND:
if (_loramac.tx_ongoing()) { if (_loramac.tx_ongoing()) {
@ -808,19 +793,11 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
break; break;
case LORAWAN_STATUS_CRYPTO_FAIL: case LORAWAN_STATUS_CRYPTO_FAIL:
tr_error("Crypto failed. Clearing TX buffers"); tr_error("Crypto failed. Clearing TX buffers");
if (_callbacks.events) { send_event_to_application(TX_CRYPTO_ERROR);
const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
break; break;
default: default:
tr_error("Failure to schedule TX!"); tr_error("Failure to schedule TX!");
if (_callbacks.events) { send_event_to_application(TX_SCHEDULING_ERROR);
const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
MBED_ASSERT(ret != 0);
(void)ret;
}
break; break;
} }
} }

View File

@ -291,12 +291,15 @@ public:
* @param null_allowed Internal use only. Needed for sending empty packet * @param null_allowed Internal use only. Needed for sending empty packet
* having CONFIRMED bit on. * having CONFIRMED bit on.
* *
* @param allow_port_0 Internal use only. Needed for flushing MAC commands.
*
* @return The number of bytes sent, or * @return The number of bytes sent, or
* LORAWAN_STATUS_WOULD_BLOCK if another TX is * LORAWAN_STATUS_WOULD_BLOCK if another TX is
* ongoing, or a negative error code on failure. * ongoing, or a negative error code on failure.
*/ */
int16_t handle_tx(uint8_t port, const uint8_t* data, 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. /** Receives a message from the Network Server.
* *
@ -399,7 +402,7 @@ private:
/** /**
* Checks if the user provided port is valid or not * 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. * State machine for stack controller layer.
@ -439,13 +442,28 @@ private:
/** /**
* Sets up user application port * 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 * Handles connection internally
*/ */
lorawan_status_t handle_connect(bool is_otaa); 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: private:
LoRaMac _loramac; LoRaMac _loramac;

View File

@ -185,6 +185,10 @@ typedef struct lorawan_connect {
* RX_TIMEOUT, - Not yet mapped * RX_TIMEOUT, - Not yet mapped
* RX_ERROR - A general RX error * RX_ERROR - A general RX error
* JOIN_FAILURE - When all Joining retries are exhausted * 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 { typedef enum lora_events {
CONNECTED=0, CONNECTED=0,
@ -198,6 +202,8 @@ typedef enum lora_events {
RX_TIMEOUT, RX_TIMEOUT,
RX_ERROR, RX_ERROR,
JOIN_FAILURE, JOIN_FAILURE,
UPLINK_REQUIRED,
AUTOMATIC_UPLINK_ERROR,
} lorawan_event_t; } lorawan_event_t;
/** /**

View File

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