Skip to content

Commit 13913c7

Browse files
authored
Merge pull request #6628 from kivaisan/mlme_indication_and_auto_uplink_config
Lora: Make automatic uplink message configurable
2 parents c6b6bab + d336cee commit 13913c7

File tree

4 files changed

+97
-92
lines changed

4 files changed

+97
-92
lines changed

features/lorawan/LoRaWANStack.cpp

Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,19 @@ using namespace events;
5858
/*****************************************************************************
5959
* Private Member Functions *
6060
****************************************************************************/
61-
bool LoRaWANStack::is_port_valid(uint8_t port)
61+
bool LoRaWANStack::is_port_valid(uint8_t port, bool allow_port_0)
6262
{
6363
//Application should not use reserved and illegal port numbers.
64-
if (port >= 224 || port == 0) {
65-
return false;
64+
if (port == 0) {
65+
return allow_port_0;
6666
} else {
6767
return true;
6868
}
6969
}
7070

71-
lorawan_status_t LoRaWANStack::set_application_port(uint8_t port)
71+
lorawan_status_t LoRaWANStack::set_application_port(uint8_t port, bool allow_port_0)
7272
{
73-
if (is_port_valid(port)) {
73+
if (is_port_valid(port, allow_port_0)) {
7474
_app_port = port;
7575
return LORAWAN_STATUS_OK;
7676
}
@@ -236,10 +236,14 @@ void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t *mlmeIndica
236236
switch( mlmeIndication->indication_type )
237237
{
238238
case MLME_SCHEDULE_UPLINK:
239-
{// The MAC signals that we shall provide an uplink as soon as possible
240-
// TODO: Sending implementation missing and will be implemented using
241-
// another task.
242-
//OnTxNextPacketTimerEvent( );
239+
{
240+
// The MAC signals that we shall provide an uplink as soon as possible
241+
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
242+
tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands...");
243+
send_automatic_uplink_message(0);
244+
#else
245+
send_event_to_application(UPLINK_REQUIRED);
246+
#endif
243247
break;
244248
}
245249
default:
@@ -332,8 +336,26 @@ lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
332336
return _loramac.set_channel_data_rate(data_rate);
333337
}
334338

339+
void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const
340+
{
341+
if (_callbacks.events) {
342+
const int ret = _queue->call(_callbacks.events, event);
343+
MBED_ASSERT(ret != 0);
344+
(void)ret;
345+
}
346+
}
347+
348+
void LoRaWANStack::send_automatic_uplink_message(const uint8_t port)
349+
{
350+
const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true);
351+
if (ret < 0) {
352+
send_event_to_application(AUTOMATIC_UPLINK_ERROR);
353+
}
354+
}
355+
335356
int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
336-
uint16_t length, uint8_t flags, bool null_allowed)
357+
uint16_t length, uint8_t flags,
358+
bool null_allowed, bool allow_port_0)
337359
{
338360
if (!null_allowed && !data) {
339361
return LORAWAN_STATUS_PARAMETER_INVALID;
@@ -364,7 +386,7 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
364386
return LORAWAN_STATUS_NO_NETWORK_JOINED;
365387
}
366388

367-
status = set_application_port(port);
389+
status = set_application_port(port, allow_port_0);
368390

369391
if (status != LORAWAN_STATUS_OK) {
370392
tr_error("Illegal application port definition.");
@@ -379,7 +401,6 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
379401

380402
int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
381403

382-
383404
status = lora_state_machine(DEVICE_STATE_SEND);
384405

385406
// 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)
501522
tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
502523
}
503524

504-
if (_callbacks.events) {
505-
const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
506-
MBED_ASSERT(ret != 0);
507-
(void)ret;
508-
}
525+
send_event_to_application(JOIN_FAILURE);
509526
}
510527
break;
511528
case MLME_LINK_CHECK:
@@ -541,21 +558,13 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
541558
tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status);
542559

543560
if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) {
544-
if (_callbacks.events) {
545-
const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
546-
MBED_ASSERT(ret != 0);
547-
(void)ret;
548-
}
561+
send_event_to_application(TX_TIMEOUT);
549562
return;
550563
} else if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) {
551564
tr_debug("Did not receive Ack");
552565
}
553566

554-
if (_callbacks.events) {
555-
const int ret = _queue->call(_callbacks.events, TX_ERROR);
556-
MBED_ASSERT(ret != 0);
557-
(void)ret;
558-
}
567+
send_event_to_application(TX_ERROR);
559568
return;
560569
}
561570

@@ -566,22 +575,14 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
566575

567576
_lw_session.uplink_counter = mcps_confirm->ul_frame_counter;
568577
_loramac.set_tx_ongoing(false);
569-
if (_callbacks.events) {
570-
const int ret = _queue->call(_callbacks.events, TX_DONE);
571-
MBED_ASSERT(ret != 0);
572-
(void)ret;
573-
}
578+
send_event_to_application(TX_DONE);
574579
}
575580

576581
void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication)
577582
{
578583
if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) {
579-
if (_callbacks.events) {
580-
tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status);
581-
const int ret = _queue->call(_callbacks.events, RX_ERROR);
582-
MBED_ASSERT(ret != 0);
583-
(void)ret;
584-
}
584+
tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status);
585+
send_event_to_application(RX_ERROR);
585586
return;
586587
}
587588

@@ -645,32 +646,28 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic
645646
tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
646647
_rx_msg.receive_ready = true;
647648

648-
if (_callbacks.events) {
649-
const int ret = _queue->call(_callbacks.events, RX_DONE);
650-
MBED_ASSERT(ret != 0);
651-
(void)ret;
652-
}
653-
654-
//TODO: below if clauses can be combined,
655-
// because those are calling same function with same parameters
656-
657-
// If fPending bit is set we try to generate an empty packet
658-
// with CONFIRMED flag set. We always set a CONFIRMED flag so
659-
// that we could retry a certain number of times if the uplink
660-
// failed for some reason
661-
if (_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) {
662-
tr_debug("Pending bit set. Sending empty message to receive pending data...");
663-
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
664-
}
665-
666-
// Class C and node received a confirmed message so we need to
667-
// send an empty packet to acknowledge the message.
668-
// This scenario is unspecified by LoRaWAN 1.0.2 specification,
669-
// but version 1.1.0 says that network SHALL not send any new
670-
// confirmed messages until ack has been sent
671-
if (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) {
672-
tr_debug("Acknowledging confirmed message (class C)...");
673-
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
649+
send_event_to_application(RX_DONE);
650+
651+
/*
652+
* If fPending bit is set we try to generate an empty packet
653+
* with CONFIRMED flag set. We always set a CONFIRMED flag so
654+
* that we could retry a certain number of times if the uplink
655+
* failed for some reason
656+
* or
657+
* Class C and node received a confirmed message so we need to
658+
* send an empty packet to acknowledge the message.
659+
* This scenario is unspecified by LoRaWAN 1.0.2 specification,
660+
* but version 1.1.0 says that network SHALL not send any new
661+
* confirmed messages until ack has been sent
662+
*/
663+
if ((_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) ||
664+
(_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED)) {
665+
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
666+
tr_debug("Sending empty uplink message...");
667+
send_automatic_uplink_message(mcps_indication->port);
668+
#else
669+
send_event_to_application(UPLINK_REQUIRED);
670+
#endif
674671
}
675672
} else {
676673
// 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)
741738
_lw_session.active = false;
742739

743740
tr_debug("LoRaWAN protocol has been shut down.");
744-
if (_callbacks.events) {
745-
const int ret = _queue->call(_callbacks.events, DISCONNECTED);
746-
MBED_ASSERT(ret != 0);
747-
(void)ret;
748-
}
741+
send_event_to_application(DISCONNECTED);
749742
status = LORAWAN_STATUS_DEVICE_OFF;
750743
break;
751744
case DEVICE_STATE_NOT_INITIALIZED:
@@ -773,11 +766,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
773766

774767
_lw_session.active = true;
775768

776-
if (_callbacks.events) {
777-
const int ret = _queue->call(_callbacks.events, CONNECTED);
778-
MBED_ASSERT(ret != 0);
779-
(void)ret;
780-
}
769+
send_event_to_application(CONNECTED);
781770
status = LORAWAN_STATUS_OK;
782771
break;
783772
case DEVICE_STATE_ABP_CONNECTING:
@@ -789,11 +778,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
789778
status = LORAWAN_STATUS_OK;
790779

791780
_lw_session.active = true;
792-
if (_callbacks.events) {
793-
const int ret = _queue->call(_callbacks.events, CONNECTED);
794-
MBED_ASSERT(ret != 0);
795-
(void)ret;
796-
}
781+
send_event_to_application(CONNECTED);
797782
break;
798783
case DEVICE_STATE_SEND:
799784
if (_loramac.tx_ongoing()) {
@@ -808,19 +793,11 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
808793
break;
809794
case LORAWAN_STATUS_CRYPTO_FAIL:
810795
tr_error("Crypto failed. Clearing TX buffers");
811-
if (_callbacks.events) {
812-
const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
813-
MBED_ASSERT(ret != 0);
814-
(void)ret;
815-
}
796+
send_event_to_application(TX_CRYPTO_ERROR);
816797
break;
817798
default:
818799
tr_error("Failure to schedule TX!");
819-
if (_callbacks.events) {
820-
const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
821-
MBED_ASSERT(ret != 0);
822-
(void)ret;
823-
}
800+
send_event_to_application(TX_SCHEDULING_ERROR);
824801
break;
825802
}
826803
}

features/lorawan/LoRaWANStack.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,15 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
291291
* @param null_allowed Internal use only. Needed for sending empty packet
292292
* having CONFIRMED bit on.
293293
*
294+
* @param allow_port_0 Internal use only. Needed for flushing MAC commands.
295+
*
294296
* @return The number of bytes sent, or
295297
* LORAWAN_STATUS_WOULD_BLOCK if another TX is
296298
* ongoing, or a negative error code on failure.
297299
*/
298300
int16_t handle_tx(uint8_t port, const uint8_t* data,
299-
uint16_t length, uint8_t flags, bool null_allowed = false);
301+
uint16_t length, uint8_t flags,
302+
bool null_allowed = false, bool allow_port_0 = false);
300303

301304
/** Receives a message from the Network Server.
302305
*
@@ -399,7 +402,7 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
399402
/**
400403
* Checks if the user provided port is valid or not
401404
*/
402-
bool is_port_valid(uint8_t port);
405+
bool is_port_valid(uint8_t port, bool allow_port_0 = false);
403406

404407
/**
405408
* State machine for stack controller layer.
@@ -439,13 +442,28 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
439442
/**
440443
* Sets up user application port
441444
*/
442-
lorawan_status_t set_application_port(uint8_t port);
445+
lorawan_status_t set_application_port(uint8_t port, bool allow_port_0 = false);
443446

444447
/**
445448
* Handles connection internally
446449
*/
447450
lorawan_status_t handle_connect(bool is_otaa);
448451

452+
453+
/** Send event to application.
454+
*
455+
* @param event The event to be sent.
456+
*/
457+
void send_event_to_application(const lorawan_event_t event) const;
458+
459+
/** Send empty uplink message to network.
460+
*
461+
* Sends an empty confirmed message to gateway.
462+
*
463+
* @param port The event to be sent.
464+
*/
465+
void send_automatic_uplink_message(const uint8_t port);
466+
449467
private:
450468

451469
LoRaMac _loramac;

features/lorawan/lorawan_types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ typedef struct lorawan_connect {
185185
* RX_TIMEOUT, - Not yet mapped
186186
* RX_ERROR - A general RX error
187187
* JOIN_FAILURE - When all Joining retries are exhausted
188+
* UPLINK_REQUIRED - Stack indicates application that some uplink needed
189+
* AUTOMATIC_UPLINK_ERROR - Stack tried automatically send uplink but some error occurred.
190+
* Application should initiate uplink as soon as possible.
191+
*
188192
*/
189193
typedef enum lora_events {
190194
CONNECTED=0,
@@ -198,6 +202,8 @@ typedef enum lora_events {
198202
RX_TIMEOUT,
199203
RX_ERROR,
200204
JOIN_FAILURE,
205+
UPLINK_REQUIRED,
206+
AUTOMATIC_UPLINK_ERROR,
201207
} lorawan_event_t;
202208

203209
/**

features/lorawan/mbed_lib.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
"lbt-on": {
6161
"help": "Enables/disables LBT. NOTE: [This feature is not yet integrated].",
6262
"value": false
63+
},
64+
"automatic-uplink-message": {
65+
"help": "Stack will automatically send an uplink message when lora server requires immediate response",
66+
"value": true
6367
}
6468
}
6569
}

0 commit comments

Comments
 (0)