mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #6628 from kivaisan/mlme_indication_and_auto_uplink_config
Lora: Make automatic uplink message configurablepull/6686/head
commit
13913c7301
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue