Skip to content

Commit 2bc8e4e

Browse files
author
Hasnain Virk
committed
Adding ack expiry handling for class C
In Class C, rx timeout does not take place for RX2 windows, so if we have not received anything, we would be retrying but if the no. of retries are maxed out, and we have not recieved anything yet, we need a mechanism to tell the upper layer that this has happened.
1 parent b0ce443 commit 2bc8e4e

File tree

4 files changed

+44
-35
lines changed

4 files changed

+44
-35
lines changed

features/lorawan/LoRaWANStack.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t& device_cla
435435
if (device_class == CLASS_B) {
436436
return LORAWAN_STATUS_UNSUPPORTED;
437437
}
438-
_loramac.set_device_class(device_class);
438+
_loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::handle_ack_expiry_for_class_c));
439439
return LORAWAN_STATUS_OK;
440440
}
441441

@@ -564,7 +564,7 @@ void LoRaWANStack::process_transmission(void)
564564
_ctrl_flags |= TX_DONE_FLAG;
565565

566566
// In Class C, reception timeout never happens, so we handle the state
567-
// progression here
567+
// progression for TX_DONE in UNCONFIRMED case here
568568
if (_loramac.get_device_class() == CLASS_C) {
569569
_loramac.post_process_mcps_req();
570570
state_controller(DEVICE_STATE_STATUS_CHECK);
@@ -573,6 +573,14 @@ void LoRaWANStack::process_transmission(void)
573573
}
574574
}
575575

576+
void LoRaWANStack::handle_ack_expiry_for_class_c(void)
577+
{
578+
_ctrl_flags &= ~TX_DONE_FLAG;
579+
_ctrl_flags |= TX_ONGOING_FLAG;
580+
tr_error("Retries exhausted for Class C device");
581+
state_controller(DEVICE_STATE_STATUS_CHECK);
582+
}
583+
576584
void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size,
577585
int16_t rssi, int8_t snr)
578586
{

features/lorawan/LoRaWANStack.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
522522
void make_tx_metadata_available(void);
523523
void make_rx_metadata_available(void);
524524

525+
void handle_ack_expiry_for_class_c(void);
526+
525527
private:
526528
LoRaMac _loramac;
527529
radio_events_t radio_events;

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,10 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
641641
_mcps_indication.buffer_size = size - ptr_pos;
642642
}
643643

644-
check_to_disable_ack_timeout(_params.is_node_ack_requested, _device_class, _mcps_confirmation.ack_received,
645-
_params.ack_timeout_retry_counter, _params.max_ack_timeout_retries );
644+
// only stop act timer, if the ack is actuall recieved
645+
if (_mcps_confirmation.ack_received) {
646+
_lora_time.stop(_params.timers.ack_timeout_timer);
647+
}
646648
}
647649

648650
void LoRaMac::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level)
@@ -775,7 +777,7 @@ bool LoRaMac::continue_joining_process()
775777

776778
bool LoRaMac::continue_sending_process()
777779
{
778-
if (_params.ack_timeout_retry_counter >= _params.max_ack_timeout_retries) {
780+
if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) {
779781
_mac_commands.clear_command_buffer();
780782
_params.adr_ack_counter++;
781783
return false;
@@ -892,38 +894,20 @@ void LoRaMac::open_rx2_window()
892894
}
893895
}
894896

895-
void LoRaMac::check_to_disable_ack_timeout(bool node_ack_requested,
896-
device_class_t dev_class,
897-
bool ack_received,
898-
uint8_t ack_timeout_retries_counter,
899-
uint8_t ack_timeout_retries)
897+
void LoRaMac::on_ack_timeout_timer_event(void)
900898
{
901-
// There are three cases where we need to stop the AckTimeoutTimer:
902-
if( node_ack_requested == false ) {
903-
if( dev_class == CLASS_C ) {
904-
// FIRST CASE
905-
// We have performed an unconfirmed uplink in class c mode
906-
// and have received a downlink in RX1 or RX2.
907-
_lora_time.stop(_params.timers.ack_timeout_timer);
908-
}
909-
} else {
910-
if( ack_received == 1 ) {
911-
// SECOND CASE
912-
// We received an ACK for previously sent confirmable message
913-
_lora_time.stop(_params.timers.ack_timeout_timer);
914-
} else {
915-
// THIRD CASE
916-
// Max number of retries exceeded for confirmable message
917-
if( ack_timeout_retries_counter > ack_timeout_retries ) {
918-
_lora_time.stop(_params.timers.ack_timeout_timer);
919-
}
899+
Lock lock(*this);
900+
901+
if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) {
902+
if (get_device_class() == CLASS_C) {
903+
// no need to use EventQueue as LoRaWANStack and LoRaMac are always
904+
// in same context
905+
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
906+
_ack_expiry_handler_for_class_c.call();
920907
}
908+
return;
921909
}
922-
}
923910

924-
void LoRaMac::on_ack_timeout_timer_event(void)
925-
{
926-
Lock lock(*this);
927911
tr_debug("ACK_TIMEOUT Elapses, Retrying ...");
928912
_lora_time.stop(_params.timers.ack_timeout_timer);
929913

@@ -1318,11 +1302,14 @@ device_class_t LoRaMac::get_device_class() const
13181302
return _device_class;
13191303
}
13201304

1321-
void LoRaMac::set_device_class(const device_class_t& device_class)
1305+
void LoRaMac::set_device_class(const device_class_t& device_class,
1306+
mbed::Callback<void(void)>ack_expiry_handler)
13221307
{
13231308
_device_class = device_class;
1309+
_ack_expiry_handler_for_class_c = ack_expiry_handler;
13241310

13251311
if (CLASS_A == _device_class) {
1312+
tr_debug("Changing device class to -> CLASS_A");
13261313
_lora_phy.put_radio_to_sleep();
13271314
} else if (CLASS_C == _device_class) {
13281315
_params.is_node_ack_requested = false;
@@ -1334,8 +1321,11 @@ void LoRaMac::set_device_class(const device_class_t& device_class)
13341321
&_params.rx_window2_config);
13351322
}
13361323
if (CLASS_C == _device_class) {
1324+
tr_debug("Changing device class to -> CLASS_C");
13371325
open_rx2_window();
13381326
}
1327+
1328+
13391329
}
13401330

13411331
void LoRaMac::setup_link_check_request()

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,10 @@ class LoRaMac {
351351
/**
352352
* @brief set_device_class Sets active device class.
353353
* @param device_class Device class to use.
354+
* @param ack_expiry_handler callback function to inform about ack expiry
354355
*/
355-
void set_device_class(const device_class_t& device_class);
356+
void set_device_class(const device_class_t& device_class,
357+
mbed::Callback<void(void)>ack_expiry_handler);
356358

357359
/**
358360
* @brief opens a continuous RX2 window for Class C devices
@@ -642,6 +644,13 @@ class LoRaMac {
642644
*/
643645
events::EventQueue *_ev_queue;
644646

647+
/**
648+
* Class C doesn't timeout in RX2 window as it is a continuous window.
649+
* We use this callback to inform the LoRaWANStack controller that the
650+
* system cannot do more retries.
651+
*/
652+
mbed::Callback<void(void)> _ack_expiry_handler_for_class_c;
653+
645654
/**
646655
* Structure to hold MCPS indication data.
647656
*/

0 commit comments

Comments
 (0)