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.
pull/6910/head
Hasnain Virk 2018-05-16 12:59:19 +03:00
parent b0ce443f5b
commit 2bc8e4e847
4 changed files with 45 additions and 36 deletions

View File

@ -435,7 +435,7 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t& device_cla
if (device_class == CLASS_B) {
return LORAWAN_STATUS_UNSUPPORTED;
}
_loramac.set_device_class(device_class);
_loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::handle_ack_expiry_for_class_c));
return LORAWAN_STATUS_OK;
}
@ -564,7 +564,7 @@ void LoRaWANStack::process_transmission(void)
_ctrl_flags |= TX_DONE_FLAG;
// In Class C, reception timeout never happens, so we handle the state
// progression here
// progression for TX_DONE in UNCONFIRMED case here
if (_loramac.get_device_class() == CLASS_C) {
_loramac.post_process_mcps_req();
state_controller(DEVICE_STATE_STATUS_CHECK);
@ -573,6 +573,14 @@ void LoRaWANStack::process_transmission(void)
}
}
void LoRaWANStack::handle_ack_expiry_for_class_c(void)
{
_ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags |= TX_ONGOING_FLAG;
tr_error("Retries exhausted for Class C device");
state_controller(DEVICE_STATE_STATUS_CHECK);
}
void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size,
int16_t rssi, int8_t snr)
{

View File

@ -522,6 +522,8 @@ private:
void make_tx_metadata_available(void);
void make_rx_metadata_available(void);
void handle_ack_expiry_for_class_c(void);
private:
LoRaMac _loramac;
radio_events_t radio_events;

View File

@ -641,8 +641,10 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
_mcps_indication.buffer_size = size - ptr_pos;
}
check_to_disable_ack_timeout(_params.is_node_ack_requested, _device_class, _mcps_confirmation.ack_received,
_params.ack_timeout_retry_counter, _params.max_ack_timeout_retries );
// only stop act timer, if the ack is actuall recieved
if (_mcps_confirmation.ack_received) {
_lora_time.stop(_params.timers.ack_timeout_timer);
}
}
void LoRaMac::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level)
@ -775,7 +777,7 @@ bool LoRaMac::continue_joining_process()
bool LoRaMac::continue_sending_process()
{
if (_params.ack_timeout_retry_counter >= _params.max_ack_timeout_retries) {
if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) {
_mac_commands.clear_command_buffer();
_params.adr_ack_counter++;
return false;
@ -892,38 +894,20 @@ void LoRaMac::open_rx2_window()
}
}
void LoRaMac::check_to_disable_ack_timeout(bool node_ack_requested,
device_class_t dev_class,
bool ack_received,
uint8_t ack_timeout_retries_counter,
uint8_t ack_timeout_retries)
{
// There are three cases where we need to stop the AckTimeoutTimer:
if( node_ack_requested == false ) {
if( dev_class == CLASS_C ) {
// FIRST CASE
// We have performed an unconfirmed uplink in class c mode
// and have received a downlink in RX1 or RX2.
_lora_time.stop(_params.timers.ack_timeout_timer);
}
} else {
if( ack_received == 1 ) {
// SECOND CASE
// We received an ACK for previously sent confirmable message
_lora_time.stop(_params.timers.ack_timeout_timer);
} else {
// THIRD CASE
// Max number of retries exceeded for confirmable message
if( ack_timeout_retries_counter > ack_timeout_retries ) {
_lora_time.stop(_params.timers.ack_timeout_timer);
}
}
}
}
void LoRaMac::on_ack_timeout_timer_event(void)
{
Lock lock(*this);
if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) {
if (get_device_class() == CLASS_C) {
// no need to use EventQueue as LoRaWANStack and LoRaMac are always
// in same context
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
_ack_expiry_handler_for_class_c.call();
}
return;
}
tr_debug("ACK_TIMEOUT Elapses, Retrying ...");
_lora_time.stop(_params.timers.ack_timeout_timer);
@ -1318,11 +1302,14 @@ device_class_t LoRaMac::get_device_class() const
return _device_class;
}
void LoRaMac::set_device_class(const device_class_t& device_class)
void LoRaMac::set_device_class(const device_class_t& device_class,
mbed::Callback<void(void)>ack_expiry_handler)
{
_device_class = device_class;
_ack_expiry_handler_for_class_c = ack_expiry_handler;
if (CLASS_A == _device_class) {
tr_debug("Changing device class to -> CLASS_A");
_lora_phy.put_radio_to_sleep();
} else if (CLASS_C == _device_class) {
_params.is_node_ack_requested = false;
@ -1334,8 +1321,11 @@ void LoRaMac::set_device_class(const device_class_t& device_class)
&_params.rx_window2_config);
}
if (CLASS_C == _device_class) {
tr_debug("Changing device class to -> CLASS_C");
open_rx2_window();
}
}
void LoRaMac::setup_link_check_request()

View File

@ -351,8 +351,10 @@ public:
/**
* @brief set_device_class Sets active device class.
* @param device_class Device class to use.
* @param ack_expiry_handler callback function to inform about ack expiry
*/
void set_device_class(const device_class_t& device_class);
void set_device_class(const device_class_t& device_class,
mbed::Callback<void(void)>ack_expiry_handler);
/**
* @brief opens a continuous RX2 window for Class C devices
@ -642,6 +644,13 @@ private:
*/
events::EventQueue *_ev_queue;
/**
* Class C doesn't timeout in RX2 window as it is a continuous window.
* We use this callback to inform the LoRaWANStack controller that the
* system cannot do more retries.
*/
mbed::Callback<void(void)> _ack_expiry_handler_for_class_c;
/**
* Structure to hold MCPS indication data.
*/