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 *
|
* 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue