Skip to content

Commit 952930c

Browse files
author
Cruz Monrreal
authored
Merge pull request #7495 from hasnainvirk/scheduling_failure_report
LoRaWAN: Reporting scheduling failures
2 parents 2261ad2 + b07c3e7 commit 952930c

File tree

4 files changed

+76
-26
lines changed

4 files changed

+76
-26
lines changed

features/lorawan/LoRaWANStack.cpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data,
332332
return status;
333333
}
334334

335-
// All the flags mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be
335+
// All the flags are mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be
336336
// used for uplink.
337337
switch (flags & MSG_FLAG_MASK) {
338338
case MSG_UNCONFIRMED_FLAG:
@@ -631,6 +631,13 @@ void LoRaWANStack::handle_ack_expiry_for_class_c(void)
631631
state_controller(DEVICE_STATE_STATUS_CHECK);
632632
}
633633

634+
void LoRaWANStack::handle_scheduling_failure(void)
635+
{
636+
tr_error("Failed to schedule transmission");
637+
state_controller(DEVICE_STATE_STATUS_CHECK);
638+
state_machine_run_to_completion();
639+
}
640+
634641
void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size,
635642
int16_t rssi, int8_t snr)
636643
{
@@ -948,22 +955,26 @@ void LoRaWANStack::mlme_confirm_handler()
948955

949956
void LoRaWANStack::mcps_confirm_handler()
950957
{
951-
// success case
952-
if (_loramac.get_mcps_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_OK) {
953-
_lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter;
954-
send_event_to_application(TX_DONE);
955-
return;
956-
}
958+
switch (_loramac.get_mcps_confirmation()->status) {
957959

958-
// failure case
959-
if (_loramac.get_mcps_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) {
960-
tr_error("Fatal Error, Radio failed to transmit");
961-
send_event_to_application(TX_TIMEOUT);
962-
return;
963-
}
960+
case LORAMAC_EVENT_INFO_STATUS_OK:
961+
_lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter;
962+
send_event_to_application(TX_DONE);
963+
break;
964+
965+
case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT:
966+
tr_error("Fatal Error, Radio failed to transmit");
967+
send_event_to_application(TX_TIMEOUT);
968+
break;
964969

965-
// if no ack was received, send TX_ERROR
966-
send_event_to_application(TX_ERROR);
970+
case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR:
971+
send_event_to_application(TX_SCHEDULING_ERROR);
972+
break;
973+
974+
default:
975+
// if no ack was received after enough retries, send TX_ERROR
976+
send_event_to_application(TX_ERROR);
977+
}
967978
}
968979

969980
void LoRaWANStack::mcps_indication_handler()
@@ -1090,11 +1101,13 @@ void LoRaWANStack::process_status_check_state()
10901101
{
10911102
if (_device_current_state == DEVICE_STATE_SENDING ||
10921103
_device_current_state == DEVICE_STATE_AWAITING_ACK) {
1093-
// this happens after RX2 slot is exhausted
1094-
// we may or may not have a successful UNCONFIRMED transmission
1104+
// If there was a successful transmission, this block gets a kick after
1105+
// RX2 slot is exhausted. We may or may not have a successful UNCONFIRMED transmission
10951106
// here. In CONFIRMED case this block is invoked only
10961107
// when the MAX number of retries are exhausted, i.e., only error
10971108
// case will fall here. Moreover, it will happen for Class A only.
1109+
// Another possibility is the case when the stack fails to schedule a
1110+
// deferred transmission and a scheduling failure handler is invoked.
10981111
_ctrl_flags &= ~TX_DONE_FLAG;
10991112
_ctrl_flags &= ~TX_ONGOING_FLAG;
11001113
_loramac.set_tx_ongoing(false);
@@ -1217,7 +1230,8 @@ void LoRaWANStack::process_idle_state(lorawan_status_t &op_status)
12171230

12181231
void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status)
12191232
{
1220-
op_status = _loramac.initialize(_queue);
1233+
op_status = _loramac.initialize(_queue, mbed::callback(this,
1234+
&LoRaWANStack::handle_scheduling_failure));
12211235

12221236
if (op_status == LORAWAN_STATUS_OK) {
12231237
_device_current_state = DEVICE_STATE_IDLE;

features/lorawan/LoRaWANStack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
484484
void make_rx_metadata_available(void);
485485

486486
void handle_ack_expiry_for_class_c(void);
487+
void handle_scheduling_failure(void);
487488

488489
private:
489490
LoRaMac _loramac;

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -839,10 +839,12 @@ lorawan_status_t LoRaMac::handle_retransmission()
839839
void LoRaMac::on_backoff_timer_expiry(void)
840840
{
841841
Lock lock(*this);
842+
842843
_lora_time.stop(_params.timers.backoff_timer);
843-
lorawan_status_t status = schedule_tx();
844-
MBED_ASSERT(status == LORAWAN_STATUS_OK);
845-
(void) status;
844+
845+
if ((schedule_tx() != LORAWAN_STATUS_OK) && nwk_joined()) {
846+
_scheduling_failure_handler.call();
847+
}
846848
}
847849

848850
void LoRaMac::open_rx1_window(void)
@@ -927,8 +929,12 @@ void LoRaMac::on_ack_timeout_timer_event(void)
927929

928930
_mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter;
929931

932+
930933
// Schedule a retry
931-
if (handle_retransmission() != LORAWAN_STATUS_OK) {
934+
lorawan_status_t status = handle_retransmission();
935+
936+
if (status == LORAWAN_STATUS_NO_CHANNEL_FOUND ||
937+
status == LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND) {
932938
// In a case when enabled channels are not found, PHY layer
933939
// resorts to default channels. Next attempt should go forward as the
934940
// default channels are always available if there is a base station in the
@@ -939,10 +945,24 @@ void LoRaMac::on_ack_timeout_timer_event(void)
939945
_mcps_confirmation.ack_received = false;
940946
_mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter;
941947

942-
// now that is a critical failure
943-
lorawan_status_t status = handle_retransmission();
948+
// For the next attempt we need to make sure that we do not incur length error
949+
// which would mean that the datarate changed during retransmissions and
950+
// the original packet doesn't fit into allowed payload buffer anymore.
951+
status = handle_retransmission();
952+
953+
if (status == LORAWAN_STATUS_LENGTH_ERROR) {
954+
_scheduling_failure_handler.call();
955+
return;
956+
}
957+
958+
// if we did not incur a length error and still the status is not OK,
959+
// it is a critical failure
960+
status = handle_retransmission();
944961
MBED_ASSERT(status == LORAWAN_STATUS_OK);
945962
(void) status;
963+
} else if (status != LORAWAN_STATUS_OK) {
964+
_scheduling_failure_handler.call();
965+
return;
946966
}
947967

948968
_params.ack_timeout_retry_counter++;
@@ -1064,6 +1084,7 @@ lorawan_status_t LoRaMac::schedule_tx()
10641084
switch (status) {
10651085
case LORAWAN_STATUS_NO_CHANNEL_FOUND:
10661086
case LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND:
1087+
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
10671088
return status;
10681089
case LORAWAN_STATUS_DUTYCYCLE_RESTRICTED:
10691090
if (backoff_time != 0) {
@@ -1713,12 +1734,14 @@ void LoRaMac::set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx
17131734
_lora_phy->set_tx_cont_mode(&continuous_wave);
17141735
}
17151736

1716-
lorawan_status_t LoRaMac::initialize(EventQueue *queue)
1737+
lorawan_status_t LoRaMac::initialize(EventQueue *queue,
1738+
mbed::Callback<void(void)>scheduling_failure_handler)
17171739
{
17181740
_lora_time.activate_timer_subsystem(queue);
17191741
_lora_phy->initialize(&_lora_time);
17201742

17211743
_ev_queue = queue;
1744+
_scheduling_failure_handler = scheduling_failure_handler;
17221745

17231746
_channel_plan.activate_channelplan_subsystem(_lora_phy);
17241747

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,15 @@ class LoRaMac {
7878
*
7979
* @param queue [in] A pointer to the application provided EventQueue.
8080
*
81+
* @param scheduling_failure_handler A callback to inform upper layer if a deferred
82+
* transmission (after backoff or retry) fails to schedule.
83+
*
8184
* @return `lorawan_status_t` The status of the operation. The possible values are:
8285
* \ref LORAWAN_STATUS_OK
8386
* \ref LORAWAN_STATUS_PARAMETER_INVALID
8487
*/
85-
lorawan_status_t initialize(events::EventQueue *queue);
88+
lorawan_status_t initialize(events::EventQueue *queue,
89+
mbed::Callback<void(void)>scheduling_failure_handler);
8690

8791
/**
8892
* @brief Disconnect LoRaMac layer
@@ -666,6 +670,14 @@ class LoRaMac {
666670
*/
667671
mbed::Callback<void(void)> _ack_expiry_handler_for_class_c;
668672

673+
/**
674+
* Transmission is async, i.e., a call to schedule_tx() may be deferred to
675+
* a time after a certain back off. We use this callback to inform the
676+
* controller layer that a specific TX transaction failed to schedule after
677+
* backoff or retry.
678+
*/
679+
mbed::Callback<void(void)> _scheduling_failure_handler;
680+
669681
/**
670682
* Structure to hold MCPS indication data.
671683
*/

0 commit comments

Comments
 (0)