Merge pull request #8405 from hasnainvirk/QOS_impl_with_utests

[LoRaWAN]: Adding QOS in response to LinkADRReq and fixing class C bugs
pull/8436/merge
Cruz Monrreal 2018-10-16 15:47:50 -05:00 committed by GitHub
commit adf9165af2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 448 additions and 221 deletions

View File

@ -527,7 +527,7 @@ TEST_F(Test_LoRaMac, get_backoff_timer_event_id)
TEST_F(Test_LoRaMac, clear_tx_pipe) TEST_F(Test_LoRaMac, clear_tx_pipe)
{ {
EXPECT_EQ(LORAWAN_STATUS_OK, object->clear_tx_pipe()); //timer id == 0 EXPECT_EQ(LORAWAN_STATUS_NO_OP, object->clear_tx_pipe()); //timer id == 0
my_phy phy; my_phy phy;
object->bind_phy(phy); object->bind_phy(phy);
@ -543,6 +543,12 @@ TEST_F(Test_LoRaMac, clear_tx_pipe)
EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb));
EventQueue_stub::int_value = 0; EventQueue_stub::int_value = 0;
EXPECT_EQ(LORAWAN_STATUS_BUSY, object->clear_tx_pipe()); EXPECT_EQ(LORAWAN_STATUS_BUSY, object->clear_tx_pipe());
loramac_mhdr_t machdr;
machdr.bits.mtype = MCPS_UNCONFIRMED;
uint8_t buf[1];
buf[0] = 'T';
LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_DUTYCYCLE_RESTRICTED;
EXPECT_TRUE(LORAWAN_STATUS_OK == object->send(&machdr, 15, buf, 1));
EventQueue_stub::int_value = 1; EventQueue_stub::int_value = 1;
EXPECT_EQ(LORAWAN_STATUS_OK, object->clear_tx_pipe()); EXPECT_EQ(LORAWAN_STATUS_OK, object->clear_tx_pipe());
@ -558,3 +564,12 @@ TEST_F(Test_LoRaMac, get_current_slot)
object->get_current_slot(); object->get_current_slot();
} }
TEST_F(Test_LoRaMac, get_QOS_level)
{
EXPECT_EQ(1, object->get_QOS_level());
}
TEST_F(Test_LoRaMac, get_prev_QOS_level)
{
EXPECT_EQ(1, object->get_prev_QOS_level());
}

View File

@ -167,8 +167,17 @@ TEST_F(Test_LoRaPHY, calculate_backoff)
{ {
channel_params_t p[1]; channel_params_t p[1];
p[0].band = 0; p[0].band = 0;
p[0].dr_range.fields.min = DR_0;
p[0].dr_range.fields.max = DR_5;
object->get_phy_params().channels.channel_list = p; object->get_phy_params().channels.channel_list = p;
band_t b[1]; band_t b[1];
b[0].duty_cycle = 0;
b[0].higher_band_freq = 8689000;
b[0].lower_band_freq = 8687000;
b[0].max_tx_pwr = 20;
b[0].last_join_tx_time = 0;
b[0].last_tx_time = 0;
b[0].off_time = 0;
object->get_phy_params().bands.table = b; object->get_phy_params().bands.table = b;
object->calculate_backoff(false, false, false, 0, 10, 12); object->calculate_backoff(false, false, false, 0, 10, 12);
@ -180,6 +189,7 @@ TEST_F(Test_LoRaPHY, calculate_backoff)
TEST_F(Test_LoRaPHY, mask_bit_test) TEST_F(Test_LoRaPHY, mask_bit_test)
{ {
uint16_t buf; uint16_t buf;
buf = 0x08;
EXPECT_TRUE(!object->mask_bit_test(&buf, 0)); EXPECT_TRUE(!object->mask_bit_test(&buf, 0));
} }
@ -197,51 +207,58 @@ TEST_F(Test_LoRaPHY, mask_bit_clear)
TEST_F(Test_LoRaPHY, request_new_channel) TEST_F(Test_LoRaPHY, request_new_channel)
{ {
band_t b;
object->get_phy_params().bands.size = 1;
b.higher_band_freq = 8689000;
b.lower_band_freq = 8678000;
b.duty_cycle = 0;
b.last_join_tx_time = 0;
b.last_tx_time = 0;
b.max_tx_pwr = 20;
b.off_time = 0;
object->get_phy_params().bands.table = &b;
channel_params_t p; channel_params_t p;
EXPECT_TRUE(0 == object->request_new_channel(1, &p)); //First 3 channels are set to be default
p.band = 0;
p.frequency = 0; p.dr_range.fields.min = DR_0;
p.dr_range.fields.max = DR_5;
p.frequency = 8687000;
p.rx1_frequency = 0;
uint16_t dflt_msk = 0x07;
object->get_phy_params().channels.default_mask = &dflt_msk;
object->get_phy_params().channels.channel_list = &p;
object->get_phy_params().custom_channelplans_supported = true; object->get_phy_params().custom_channelplans_supported = true;
uint16_t list;
object->get_phy_params().channels.default_mask = &list;
channel_params_t pp;
object->get_phy_params().channels.channel_list = &pp;
EXPECT_TRUE(0 == object->request_new_channel(1, &p));
//Default //Default channel, PARAMETER invalid
p.frequency = 2; EXPECT_TRUE(0 == object->request_new_channel(0, &p));
EXPECT_TRUE(0 == object->request_new_channel(1, &p));
//Freq & DR invalid //Freq & DR invalid
object->get_phy_params().max_channel_cnt = 2; p.frequency = 12345;
EXPECT_TRUE(0 == object->request_new_channel(1, &p)); p.dr_range.fields.max = 12;
object->get_phy_params().max_channel_cnt = 16;
object->get_phy_params().min_tx_datarate = DR_0;
object->get_phy_params().max_tx_datarate = DR_5;
// Frequency and DR are invalid - LORAWAN_STATUS_FREQ_AND_DR_INVALID
EXPECT_TRUE(0 == object->request_new_channel(0, &p));
//Freq invalid //Freq invalid
pp.frequency = 0; p.frequency = 12345;
object->get_phy_params().default_max_datarate = 1; p.dr_range.fields.max = DR_5;
object->get_phy_params().max_tx_datarate = 8;
p.dr_range.fields.max = 2;
p.dr_range.fields.min = 0;
object->get_phy_params().default_channel_cnt = 3; object->get_phy_params().default_channel_cnt = 3;
EXPECT_TRUE(2 == object->request_new_channel(0, &p)); EXPECT_TRUE(2 == object->request_new_channel(0, &p));
//DR invalid //DR invalid
pp.frequency = 2; p.frequency = 8687000;
p.band = 0;
object->get_phy_params().bands.size = 1;
band_t b;
object->get_phy_params().bands.table = &b;
b.higher_band_freq = 5;
b.lower_band_freq = 1;
p.dr_range.fields.max = 12; p.dr_range.fields.max = 12;
p.dr_range.fields.min = 1; p.dr_range.fields.min = 1;
EXPECT_TRUE(1 == object->request_new_channel(0, &p)); EXPECT_TRUE(1 == object->request_new_channel(0, &p));
//STATUS_OK //STATUS_OK
p.dr_range.fields.max = 2; p.dr_range.fields.max = DR_5;
uint16_t list2[16]; p.dr_range.fields.min = DR_0;
p.dr_range.fields.min = 0; uint16_t ch_msk = 0x08;
object->get_phy_params().channels.mask = list2; object->get_phy_params().channels.mask = &ch_msk;
EXPECT_TRUE(3 == object->request_new_channel(0, &p)); EXPECT_TRUE(3 == object->request_new_channel(0, &p));
} }
@ -272,19 +289,27 @@ TEST_F(Test_LoRaPHY, restore_default_channels)
TEST_F(Test_LoRaPHY, apply_cf_list) TEST_F(Test_LoRaPHY, apply_cf_list)
{ {
uint8_t list[16]; uint8_t list[16];
memset(list, 0, 16);
object->apply_cf_list(list, 0); object->apply_cf_list(list, 0);
object->get_phy_params().cflist_supported = true; object->get_phy_params().cflist_supported = true;
object->apply_cf_list(list, 0); object->apply_cf_list(list, 0);
object->get_phy_params().default_channel_cnt = 2; object->get_phy_params().default_channel_cnt = 1;
object->get_phy_params().cflist_channel_cnt = 0; object->get_phy_params().cflist_channel_cnt = 0;
object->get_phy_params().max_channel_cnt = 3; object->get_phy_params().max_channel_cnt = 3;
uint16_t mask[8]; uint16_t def_mask = 0x01;
channel_params_t p[8]; channel_params_t p[16];
object->get_phy_params().channels.default_mask = mask; memset(p, 0, 16);
object->get_phy_params().channels.mask = mask; //one default channel
p[0].band = 0;
p[0].dr_range.fields.min = DR_0;
p[0].dr_range.fields.min = DR_5;
p[0].frequency = 8687000;
object->get_phy_params().channels.default_mask = &def_mask;
object->get_phy_params().channels.mask = &def_mask;
object->get_phy_params().channels.channel_list = p; object->get_phy_params().channels.channel_list = p;
object->apply_cf_list(list, 16); object->apply_cf_list(list, 16);
@ -325,6 +350,7 @@ TEST_F(Test_LoRaPHY, rx_config)
uint8_t list2; uint8_t list2;
object->get_phy_params().payloads_with_repeater.table = &list2; object->get_phy_params().payloads_with_repeater.table = &list2;
rx_config_params_t p; rx_config_params_t p;
memset(&p, 0, sizeof(rx_config_params_t));
p.datarate = 0; p.datarate = 0;
p.rx_slot = RX_SLOT_WIN_1; p.rx_slot = RX_SLOT_WIN_1;
channel_params_t pp[1]; channel_params_t pp[1];
@ -345,11 +371,22 @@ TEST_F(Test_LoRaPHY, rx_config)
TEST_F(Test_LoRaPHY, compute_rx_win_params) TEST_F(Test_LoRaPHY, compute_rx_win_params)
{ {
uint32_t list[1]; uint32_t list[1];
list[0] = 0; list[0] = 125000;
object->get_phy_params().bandwidths.table = list; object->get_phy_params().bandwidths.table = list;
uint8_t list2; uint8_t list2[1];
list2[0]= 12;
object->get_phy_params().datarates.table = &list2; object->get_phy_params().datarates.table = &list2;
channel_params_t ch_lst[16];
memset(ch_lst, 0, sizeof(channel_params_t)*16);
ch_lst[0].band = 0;
ch_lst[0].dr_range.fields.min = DR_0;
ch_lst[0].dr_range.fields.max = DR_5;
ch_lst[0].frequency = 8687000;
object->get_phy_params().channels.channel_list = ch_lst;
object->get_phy_params().channels.channel_list_size = 16;
rx_config_params_t p; rx_config_params_t p;
memset(&p, 0, sizeof(rx_config_params_t));
p.frequency = 8687000;
object->compute_rx_win_params(0, 0, 0, &p); object->compute_rx_win_params(0, 0, 0, &p);
p.datarate = 0; p.datarate = 0;
@ -368,20 +405,25 @@ TEST_F(Test_LoRaPHY, compute_rx_win_params)
TEST_F(Test_LoRaPHY, tx_config) TEST_F(Test_LoRaPHY, tx_config)
{ {
band_t b; band_t b;
memset(&b, 0, sizeof(band_t));
object->get_phy_params().bands.table = &b; object->get_phy_params().bands.table = &b;
channel_params_t pp; channel_params_t pp;
memset(&pp, 0, sizeof(channel_params_t));
pp.band=0; pp.band=0;
object->get_phy_params().channels.channel_list = &pp; object->get_phy_params().channels.channel_list = &pp;
uint32_t list = 0; uint32_t list[1];
list[0] = 125000;
object->get_phy_params().bandwidths.table = &list; object->get_phy_params().bandwidths.table = &list;
uint8_t list2; uint8_t list2[1];
list2[0] = 12;
object->get_phy_params().datarates.table = &list2; object->get_phy_params().datarates.table = &list2;
my_radio radio; my_radio radio;
object->set_radio_instance(radio); object->set_radio_instance(radio);
tx_config_params_t p; tx_config_params_t p;
memset(&p, 0, sizeof(tx_config_params_t));
p.channel=0; p.channel=0;
int8_t i; int8_t i = 20;
lorawan_time_t t; lorawan_time_t t = 36;
object->tx_config(&p, &i, &t); object->tx_config(&p, &i, &t);
p.datarate = 8; p.datarate = 8;
@ -392,7 +434,9 @@ TEST_F(Test_LoRaPHY, tx_config)
TEST_F(Test_LoRaPHY, link_ADR_request) TEST_F(Test_LoRaPHY, link_ADR_request)
{ {
adr_req_params_t p; adr_req_params_t p;
memset(&p, 0, sizeof(adr_req_params_t));
uint8_t b[100]; uint8_t b[100];
memset(b, 0, 100);
p.payload = b; p.payload = b;
b[0] = 0x03; b[0] = 0x03;
b[1] = 1; b[1] = 1;
@ -411,16 +455,17 @@ TEST_F(Test_LoRaPHY, link_ADR_request)
b[14] = 0; b[14] = 0;
b[15] = 0; b[15] = 0;
p.payload_size = 16; p.payload_size = 16;
int8_t i, j; int8_t i = 0, j = 0;
uint8_t k, l; uint8_t k = 0, l = 0;
uint8_t t[5]; uint8_t t[5] = {12, 11, 10, 9, 8};
t[0] = 0; t[0] = 0;
object->get_phy_params().datarates.size = 1; object->get_phy_params().datarates.size = 5;
object->get_phy_params().datarates.table = t; object->get_phy_params().datarates.table = t;
//Test without ADR payload does not make sense here. //Test without ADR payload does not make sense here.
object->get_phy_params().max_channel_cnt = 2; object->get_phy_params().max_channel_cnt = 16;
channel_params_t li[4]; channel_params_t li[16];
memset(li, 0, sizeof(channel_params_t)*16);
object->get_phy_params().channels.channel_list = li; object->get_phy_params().channels.channel_list = li;
li[0].frequency = 0; li[0].frequency = 0;
li[1].frequency = 5; li[1].frequency = 5;
@ -430,7 +475,7 @@ TEST_F(Test_LoRaPHY, link_ADR_request)
//verify adr with p.adr_enabled = false //verify adr with p.adr_enabled = false
EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l)); EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l));
p.current_nb_rep = 0; p.current_nb_trans = 0;
EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l)); EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l));
p.adr_enabled = true; p.adr_enabled = true;
@ -484,9 +529,19 @@ TEST_F(Test_LoRaPHY, link_ADR_request)
TEST_F(Test_LoRaPHY, accept_rx_param_setup_req) TEST_F(Test_LoRaPHY, accept_rx_param_setup_req)
{ {
my_radio radio; my_radio radio;
radio.bool_value = true;
object->set_radio_instance(radio); object->set_radio_instance(radio);
rx_param_setup_req_t req; rx_param_setup_req_t req;
EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&req)); req.datarate = DR_0;
req.dr_offset = 0;
req.frequency = 8678000;
band_t band[1];
memset(band, 0, sizeof(band_t));
band[0].higher_band_freq = 8688000;
band[0].lower_band_freq = 8666000;
object->get_phy_params().bands.size = 1;
object->get_phy_params().bands.table = band;
EXPECT_TRUE(0x07 == object->accept_rx_param_setup_req(&req));
} }
TEST_F(Test_LoRaPHY, accept_tx_param_setup_req) TEST_F(Test_LoRaPHY, accept_tx_param_setup_req)
@ -504,8 +559,14 @@ TEST_F(Test_LoRaPHY, dl_channel_request)
object->get_phy_params().dl_channel_req_supported = true; object->get_phy_params().dl_channel_req_supported = true;
object->get_phy_params().bands.size = 1; object->get_phy_params().bands.size = 1;
band_t t[1]; band_t t[1];
memset(t, 0, sizeof(band_t));
t[0].higher_band_freq = 8688000;
t[0].lower_band_freq = 8668000;
object->get_phy_params().bands.size = 1;
object->get_phy_params().bands.table = t; object->get_phy_params().bands.table = t;
channel_params_t p[4]; channel_params_t p[16];
memset(p, 0, sizeof(channel_params_t) * 16);
object->get_phy_params().channels.channel_list_size = 16;
object->get_phy_params().channels.channel_list = p; object->get_phy_params().channels.channel_list = p;
p[0].frequency = 0; p[0].frequency = 0;
@ -533,15 +594,21 @@ TEST_F(Test_LoRaPHY, get_alternate_DR)
TEST_F(Test_LoRaPHY, set_next_channel) TEST_F(Test_LoRaPHY, set_next_channel)
{ {
channel_selection_params_t p; channel_selection_params_t p;
uint8_t ch; memset(&p, 0, sizeof(channel_selection_params_t));
lorawan_time_t t1; band_t band[1];
lorawan_time_t t2; memset(band, 0, sizeof(band_t));
band[0].higher_band_freq = 8687000;
object->get_phy_params().bands.size = 1;
object->get_phy_params().bands.table = band;
uint8_t ch = 5;
lorawan_time_t t1 = 16;
lorawan_time_t t2 = 32;
p.aggregate_timeoff = 10000; p.aggregate_timeoff = 10000;
EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2)); EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2));
uint16_t list[16]; uint16_t list[16];
memset(list, 0, 16);
list[4] = 1; list[4] = 1;
memcpy(list, "\0", 16);
object->get_phy_params().channels.mask = list; object->get_phy_params().channels.mask = list;
object->get_phy_params().channels.mask_size = 1; object->get_phy_params().channels.mask_size = 1;
p.aggregate_timeoff = 10000; p.aggregate_timeoff = 10000;
@ -553,6 +620,7 @@ TEST_F(Test_LoRaPHY, set_next_channel)
p.joined = false; p.joined = false;
p.dc_enabled = false; p.dc_enabled = false;
band_t b[4]; band_t b[4];
memset(b, 0, sizeof(band_t)*4);
object->get_phy_params().bands.size = 2; object->get_phy_params().bands.size = 2;
object->get_phy_params().bands.table = &b; object->get_phy_params().bands.table = &b;
b[0].off_time = 0; b[0].off_time = 0;

View File

@ -201,7 +201,7 @@ TEST_F(Test_LoRaWANInterface, add_app_callbacks)
TEST_F(Test_LoRaWANInterface, set_device_class) TEST_F(Test_LoRaWANInterface, set_device_class)
{ {
object->set_device_class(CLASS_A); EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A));
} }
TEST_F(Test_LoRaWANInterface, get_tx_metadata) TEST_F(Test_LoRaWANInterface, get_tx_metadata)

View File

@ -350,6 +350,9 @@ TEST_F(Test_LoRaWANStack, handle_tx)
cb.events = events_cb; cb.events = events_cb;
cb.link_check_resp = lc_resp; cb.link_check_resp = lc_resp;
cb.battery_level = batt_lvl; cb.battery_level = batt_lvl;
struct equeue_event ptr;
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true;
EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb));
EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_link_check_request()); EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_link_check_request());
@ -394,6 +397,10 @@ TEST_F(Test_LoRaWANStack, handle_rx)
LoRaMac_stub::status_value = LORAWAN_STATUS_OK; LoRaMac_stub::status_value = LORAWAN_STATUS_OK;
EXPECT_TRUE(LORAWAN_STATUS_NO_ACTIVE_SESSIONS == object->handle_rx(NULL, 0, port, flags, false)); EXPECT_TRUE(LORAWAN_STATUS_NO_ACTIVE_SESSIONS == object->handle_rx(NULL, 0, port, flags, false));
struct equeue_event ptr;
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true;
lorawan_connect_t conn; lorawan_connect_t conn;
conn.connect_type = LORAWAN_CONNECTION_ABP; conn.connect_type = LORAWAN_CONNECTION_ABP;
EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn));
@ -410,14 +417,13 @@ TEST_F(Test_LoRaWANStack, handle_rx)
my_LoRaPHY phy; my_LoRaPHY phy;
object->bind_phy_and_radio_driver(radio, phy); object->bind_phy_and_radio_driver(radio, phy);
struct equeue_event ptr;
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true;
loramac_mcps_confirm_t conf; loramac_mcps_confirm_t conf;
conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mcps_conf_ptr = &conf; LoRaMac_stub::mcps_conf_ptr = &conf;
radio._ev->tx_done(); radio._ev->tx_done();
loramac_mcps_indication_t ind; loramac_mcps_indication_t ind;
ind.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mcps_ind_ptr = &ind; LoRaMac_stub::mcps_ind_ptr = &ind;
loramac_mlme_confirm_t mlme; loramac_mlme_confirm_t mlme;
@ -429,7 +435,7 @@ TEST_F(Test_LoRaWANStack, handle_rx)
conf.req_type = MCPS_PROPRIETARY; conf.req_type = MCPS_PROPRIETARY;
ind.pending = true; ind.pending = true;
LoRaMac_stub::dev_class_value = CLASS_C; LoRaMac_stub::dev_class_value = CLASS_A;
loramac_mlme_indication_t mlme_ind; loramac_mlme_indication_t mlme_ind;
mlme_ind.pending = false; mlme_ind.pending = false;
@ -546,11 +552,6 @@ TEST_F(Test_LoRaWANStack, set_device_class)
EXPECT_TRUE(LORAWAN_STATUS_UNSUPPORTED == object->set_device_class(CLASS_B)); EXPECT_TRUE(LORAWAN_STATUS_UNSUPPORTED == object->set_device_class(CLASS_B));
EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A));
//Visit callback
if (LoRaMac_stub::_ack_expiry_handler_for_class_c) {
LoRaMac_stub::_ack_expiry_handler_for_class_c.call();
}
} }
TEST_F(Test_LoRaWANStack, acquire_tx_metadata) TEST_F(Test_LoRaWANStack, acquire_tx_metadata)
@ -574,9 +575,13 @@ TEST_F(Test_LoRaWANStack, acquire_tx_metadata)
equeue_stub.void_ptr = &ptr; equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true; equeue_stub.call_cb_immediately = true;
loramac_mcps_confirm_t conf; loramac_mcps_confirm_t conf;
conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mcps_conf_ptr = &conf; LoRaMac_stub::mcps_conf_ptr = &conf;
radio._ev->tx_done(); radio._ev->tx_done();
LoRaMac_stub::slot_value = RX_SLOT_WIN_2;
radio._ev->rx_timeout();
EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_tx_metadata(data)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_tx_metadata(data));
} }
@ -601,13 +606,16 @@ TEST_F(Test_LoRaWANStack, acquire_rx_metadata)
equeue_stub.void_ptr = &ptr; equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true; equeue_stub.call_cb_immediately = true;
loramac_mcps_confirm_t conf; loramac_mcps_confirm_t conf;
conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mcps_conf_ptr = &conf; LoRaMac_stub::mcps_conf_ptr = &conf;
radio._ev->tx_done(); radio._ev->tx_done();
loramac_mcps_indication_t ind; loramac_mcps_indication_t ind;
ind.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mcps_ind_ptr = &ind; LoRaMac_stub::mcps_ind_ptr = &ind;
loramac_mlme_confirm_t mlme; loramac_mlme_confirm_t mlme;
mlme.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::mlme_conf_ptr = &mlme; LoRaMac_stub::mlme_conf_ptr = &mlme;
mlme.pending = true; mlme.pending = true;
mlme.req_type = MLME_JOIN; mlme.req_type = MLME_JOIN;
@ -631,6 +639,7 @@ TEST_F(Test_LoRaWANStack, acquire_rx_metadata)
EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb));
mlme.req_type = MLME_LINK_CHECK; mlme.req_type = MLME_LINK_CHECK;
mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; mlme.status = LORAMAC_EVENT_INFO_STATUS_OK;
LoRaMac_stub::bool_true_counter = true;
radio._ev->rx_done(NULL, 0, 0, 0); radio._ev->rx_done(NULL, 0, 0, 0);
EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_rx_metadata(data)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_rx_metadata(data));
@ -658,7 +667,7 @@ TEST_F(Test_LoRaWANStack, stop_sending)
EventQueue queue; EventQueue queue;
EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue));
LoRaMac_stub::status_value = LORAWAN_STATUS_DEVICE_OFF; LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY;
EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->stop_sending()); EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->stop_sending());
LoRaMac_stub::status_value = LORAWAN_STATUS_OK; LoRaMac_stub::status_value = LORAWAN_STATUS_OK;
@ -851,7 +860,7 @@ TEST_F(Test_LoRaWANStack, process_reception)
conf.req_type = MCPS_UNCONFIRMED; conf.req_type = MCPS_UNCONFIRMED;
LoRaMac_stub::dev_class_value = CLASS_A; LoRaMac_stub::dev_class_value = CLASS_A;
LoRaMac_stub::bool_value = true; LoRaMac_stub::bool_true_counter++;
mlme_ind.pending = true; mlme_ind.pending = true;
mlme_ind.indication_type = MLME_SCHEDULE_UPLINK; mlme_ind.indication_type = MLME_SCHEDULE_UPLINK;
conf.status = LORAMAC_EVENT_INFO_STATUS_ERROR; conf.status = LORAMAC_EVENT_INFO_STATUS_ERROR;

View File

@ -26,6 +26,7 @@ int LoRaMac_stub::bool_false_counter = 0;
int LoRaMac_stub::bool_true_counter = 0; int LoRaMac_stub::bool_true_counter = 0;
bool LoRaMac_stub::bool_value = false; bool LoRaMac_stub::bool_value = false;
int LoRaMac_stub::int_value = 0; int LoRaMac_stub::int_value = 0;
uint8_t LoRaMac_stub::uint8_value = 1;
rx_slot_t LoRaMac_stub::slot_value = RX_SLOT_WIN_1; rx_slot_t LoRaMac_stub::slot_value = RX_SLOT_WIN_1;
lorawan_status_t LoRaMac_stub::status_value = LORAWAN_STATUS_OK; lorawan_status_t LoRaMac_stub::status_value = LORAWAN_STATUS_OK;
loramac_mcps_confirm_t *LoRaMac_stub::mcps_conf_ptr = NULL; loramac_mcps_confirm_t *LoRaMac_stub::mcps_conf_ptr = NULL;
@ -33,10 +34,8 @@ loramac_mcps_indication_t *LoRaMac_stub::mcps_ind_ptr = NULL;
loramac_mlme_confirm_t *LoRaMac_stub::mlme_conf_ptr = NULL; loramac_mlme_confirm_t *LoRaMac_stub::mlme_conf_ptr = NULL;
loramac_mlme_indication_t *LoRaMac_stub::mlme_ind_ptr = NULL; loramac_mlme_indication_t *LoRaMac_stub::mlme_ind_ptr = NULL;
device_class_t LoRaMac_stub::dev_class_value = CLASS_A; device_class_t LoRaMac_stub::dev_class_value = CLASS_A;
mbed::Callback<void(void)> LoRaMac_stub::_ack_expiry_handler_for_class_c = NULL;
mbed::Callback<void(void)> LoRaMac_stub::_scheduling_failure_handler = NULL; mbed::Callback<void(void)> LoRaMac_stub::_scheduling_failure_handler = NULL;
LoRaMac::LoRaMac() LoRaMac::LoRaMac()
: _lora_time(), : _lora_time(),
_lora_phy(NULL), _lora_phy(NULL),
@ -334,9 +333,8 @@ device_class_t LoRaMac::get_device_class() const
} }
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) mbed::Callback<void(void)>rx2_would_be_closure_handler)
{ {
LoRaMac_stub::_ack_expiry_handler_for_class_c = ack_expiry_handler;
} }
void LoRaMac::setup_link_check_request() void LoRaMac::setup_link_check_request()
@ -456,3 +454,13 @@ lorawan_status_t LoRaMac::multicast_channel_unlink(multicast_params_t *channel_p
void LoRaMac::bind_phy(LoRaPHY &phy) void LoRaMac::bind_phy(LoRaPHY &phy)
{ {
} }
uint8_t LoRaMac::get_QOS_level(void)
{
return LoRaMac_stub::uint8_value;
}
uint8_t LoRaMac::get_prev_QOS_level(void)
{
return LoRaMac_stub::uint8_value;
}

View File

@ -28,6 +28,7 @@ extern bool bool_value;
extern int bool_false_counter; extern int bool_false_counter;
extern int bool_true_counter; extern int bool_true_counter;
extern int int_value; extern int int_value;
extern uint8_t uint8_value;
extern rx_slot_t slot_value; extern rx_slot_t slot_value;
extern lorawan_status_t status_value; extern lorawan_status_t status_value;
extern loramac_mcps_confirm_t *mcps_conf_ptr; extern loramac_mcps_confirm_t *mcps_conf_ptr;
@ -35,6 +36,5 @@ extern loramac_mcps_indication_t *mcps_ind_ptr;
extern loramac_mlme_confirm_t *mlme_conf_ptr; extern loramac_mlme_confirm_t *mlme_conf_ptr;
extern loramac_mlme_indication_t *mlme_ind_ptr; extern loramac_mlme_indication_t *mlme_ind_ptr;
extern device_class_t dev_class_value; extern device_class_t dev_class_value;
extern mbed::Callback<void(void)> _ack_expiry_handler_for_class_c;
extern mbed::Callback<void(void)> _scheduling_failure_handler; extern mbed::Callback<void(void)> _scheduling_failure_handler;
} }

View File

@ -387,6 +387,7 @@ lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t *params,
uint8_t *channel, lorawan_time_t *time, uint8_t *channel, lorawan_time_t *time,
lorawan_time_t *aggregate_timeoff) lorawan_time_t *aggregate_timeoff)
{ {
*time = 100;
return LoRaPHY_stub::lorawan_status_value; return LoRaPHY_stub::lorawan_status_value;
} }

View File

@ -186,8 +186,14 @@ void LoRaWANStack::process_transmission(void)
{ {
} }
void LoRaWANStack::handle_ack_expiry_for_class_c(void) void post_process_tx_with_reception(void)
{ {
}
void post_process_tx_no_reception(void)
{
} }
void LoRaWANStack::handle_scheduling_failure(void) void LoRaWANStack::handle_scheduling_failure(void)
@ -295,4 +301,3 @@ void LoRaWANStack::process_idle_state(lorawan_status_t &op_status)
void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status) void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status)
{ {
} }

View File

@ -40,7 +40,7 @@ SPDX-License-Identifier: BSD-3-Clause
* Control flags for transient states * Control flags for transient states
*/ */
#define IDLE_FLAG 0x00000000 #define IDLE_FLAG 0x00000000
#define TX_ONGOING_FLAG 0x00000001 #define RETRY_EXHAUSTED_FLAG 0x00000001
#define MSG_RECVD_FLAG 0x00000002 #define MSG_RECVD_FLAG 0x00000002
#define CONNECTED_FLAG 0x00000004 #define CONNECTED_FLAG 0x00000004
#define USING_OTAA_FLAG 0x00000008 #define USING_OTAA_FLAG 0x00000008
@ -68,6 +68,7 @@ LoRaWANStack::LoRaWANStack()
_tx_metadata(), _tx_metadata(),
_rx_metadata(), _rx_metadata(),
_num_retry(1), _num_retry(1),
_qos_cnt(1),
_ctrl_flags(IDLE_FLAG), _ctrl_flags(IDLE_FLAG),
_app_port(INVALID_PORT), _app_port(INVALID_PORT),
_link_check_requested(false), _link_check_requested(false),
@ -276,7 +277,6 @@ lorawan_status_t LoRaWANStack::stop_sending(void)
if (status == LORAWAN_STATUS_OK) { if (status == LORAWAN_STATUS_OK) {
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~TX_ONGOING_FLAG;
_loramac.set_tx_ongoing(false); _loramac.set_tx_ongoing(false);
_device_current_state = DEVICE_STATE_IDLE; _device_current_state = DEVICE_STATE_IDLE;
return LORAWAN_STATUS_OK; return LORAWAN_STATUS_OK;
@ -452,7 +452,8 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_cla
if (device_class == CLASS_B) { if (device_class == CLASS_B) {
return LORAWAN_STATUS_UNSUPPORTED; return LORAWAN_STATUS_UNSUPPORTED;
} }
_loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::handle_ack_expiry_for_class_c)); _loramac.set_device_class(device_class,
mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception));
return LORAWAN_STATUS_OK; return LORAWAN_STATUS_OK;
} }
@ -562,7 +563,6 @@ void LoRaWANStack::process_transmission_timeout()
// this is a fatal error and should not happen // this is a fatal error and should not happen
tr_debug("TX Timeout"); tr_debug("TX Timeout");
_loramac.on_radio_tx_timeout(); _loramac.on_radio_tx_timeout();
_ctrl_flags &= ~TX_ONGOING_FLAG;
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
if (_device_current_state == DEVICE_STATE_JOINING) { if (_device_current_state == DEVICE_STATE_JOINING) {
mlme_confirm_handler(); mlme_confirm_handler();
@ -576,9 +576,6 @@ void LoRaWANStack::process_transmission_timeout()
void LoRaWANStack::process_transmission(void) void LoRaWANStack::process_transmission(void)
{ {
tr_debug("Transmission completed"); tr_debug("Transmission completed");
_loramac.on_radio_tx_done(_tx_timestamp);
make_tx_metadata_available();
if (_device_current_state == DEVICE_STATE_JOINING) { if (_device_current_state == DEVICE_STATE_JOINING) {
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
@ -586,31 +583,103 @@ void LoRaWANStack::process_transmission(void)
if (_device_current_state == DEVICE_STATE_SENDING) { if (_device_current_state == DEVICE_STATE_SENDING) {
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
_ctrl_flags |= TX_ONGOING_FLAG;
_ctrl_flags &= ~TX_DONE_FLAG;
tr_debug("Awaiting ACK"); tr_debug("Awaiting ACK");
_device_current_state = DEVICE_STATE_AWAITING_ACK; _device_current_state = DEVICE_STATE_AWAITING_ACK;
} else if (_loramac.get_device_class() == CLASS_A) { }
// Class A unconfirmed message sent, TX_DONE event will be sent to }
// application when RX2 windows is elapsed, i.e., in process_reception_timeout()
_ctrl_flags &= ~TX_ONGOING_FLAG; _loramac.on_radio_tx_done(_tx_timestamp);
}
void LoRaWANStack::post_process_tx_with_reception()
{
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
// if ack was not received, we will try retransmission after
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
// if ack was received. Otherwise, following method will be called in
// LoRaMac.cpp, on_ack_timeout_timer_event().
if (_loramac.get_mcps_indication()->is_ack_recvd) {
_ctrl_flags |= TX_DONE_FLAG; _ctrl_flags |= TX_DONE_FLAG;
} else if (_loramac.get_device_class() == CLASS_C) { _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
// In Class C, reception timeout never happens, so we handle the state tr_debug("Ack=OK, NbTrials=%d",
// progression for TX_DONE in UNCONFIRMED case here _loramac.get_mcps_confirmation()->nb_retries);
_loramac.post_process_mcps_req(); _loramac.post_process_mcps_req();
make_tx_metadata_available();
state_controller(DEVICE_STATE_STATUS_CHECK);
} else {
if (!_loramac.continue_sending_process()
&& _loramac.get_current_slot() != RX_SLOT_WIN_1) {
tr_error("Retries exhausted for Class %s device",
_loramac.get_device_class() == CLASS_A ? "A" : "C");
_ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags |= RETRY_EXHAUSTED_FLAG;
state_controller(DEVICE_STATE_STATUS_CHECK);
}
}
} else {
// handle UNCONFIRMED case here, RX slots were turned off due to
// valid packet reception.
uint8_t prev_QOS_level = _loramac.get_prev_QOS_level();
uint8_t QOS_level = _loramac.get_QOS_level();
// We will not apply QOS on the post-processing of the previous
// outgoing message as we would have received QOS instruction in response
// to that particular message
if (QOS_level > LORAWAN_DEFAULT_QOS && _qos_cnt < QOS_level
&& (prev_QOS_level == QOS_level)) {
_ctrl_flags &= ~TX_DONE_FLAG;
const int ret = _queue->call(this, &LoRaWANStack::state_controller,
DEVICE_STATE_SCHEDULING);
MBED_ASSERT(ret != 0);
(void) ret;
_qos_cnt++;
tr_info("QOS: repeated transmission #%d queued", _qos_cnt);
} else {
_loramac.post_process_mcps_req();
_ctrl_flags |= TX_DONE_FLAG;
make_tx_metadata_available();
state_controller(DEVICE_STATE_STATUS_CHECK); state_controller(DEVICE_STATE_STATUS_CHECK);
state_machine_run_to_completion();
} }
} }
} }
void LoRaWANStack::handle_ack_expiry_for_class_c(void) void LoRaWANStack::post_process_tx_no_reception()
{ {
_ctrl_flags &= ~TX_DONE_FLAG; if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
_ctrl_flags |= TX_ONGOING_FLAG; if (_loramac.continue_sending_process()) {
tr_error("Retries exhausted for Class C device"); _ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
return;
}
tr_error("Retries exhausted for Class %s device",
_loramac.get_device_class() == CLASS_A ? "A" : "C");
_ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags |= RETRY_EXHAUSTED_FLAG;
} else {
_ctrl_flags |= TX_DONE_FLAG;
uint8_t prev_QOS_level = _loramac.get_prev_QOS_level();
uint8_t QOS_level = _loramac.get_QOS_level();
if (QOS_level > LORAWAN_DEFAULT_QOS && (prev_QOS_level == QOS_level)) {
if (_qos_cnt < QOS_level) {
const int ret = _queue->call(this, &LoRaWANStack::state_controller,
DEVICE_STATE_SCHEDULING);
MBED_ASSERT(ret != 0);
(void)ret;
_qos_cnt++;
tr_info("QOS: repeated transmission #%d queued", _qos_cnt);
state_machine_run_to_completion();
return;
}
}
}
_loramac.post_process_mcps_req();
make_tx_metadata_available();
state_controller(DEVICE_STATE_STATUS_CHECK); state_controller(DEVICE_STATE_STATUS_CHECK);
state_machine_run_to_completion();
} }
void LoRaWANStack::handle_scheduling_failure(void) void LoRaWANStack::handle_scheduling_failure(void)
@ -620,16 +689,18 @@ void LoRaWANStack::handle_scheduling_failure(void)
state_machine_run_to_completion(); state_machine_run_to_completion();
} }
void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size, void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size,
int16_t rssi, int8_t snr) int16_t rssi, int8_t snr)
{ {
_device_current_state = DEVICE_STATE_RECEIVING; _device_current_state = DEVICE_STATE_RECEIVING;
_ctrl_flags &= ~MSG_RECVD_FLAG; _ctrl_flags &= ~MSG_RECVD_FLAG;
_ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
_loramac.on_radio_rx_done(payload, size, rssi, snr); _loramac.on_radio_rx_done(payload, size, rssi, snr);
make_rx_metadata_available();
if (_loramac.get_mlme_confirmation()->pending) { if (_loramac.get_mlme_confirmation()->pending) {
_loramac.post_process_mlme_request(); _loramac.post_process_mlme_request();
mlme_confirm_handler(); mlme_confirm_handler();
@ -645,36 +716,10 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
return; return;
} }
// if the outgoing message was of CONFIRMED type make_rx_metadata_available();
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
// if ack was not received, we will try retransmission after // Post process transmission in response to the reception
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer post_process_tx_with_reception();
// if ack was received. Otherwise, following method will be called in
// LoRaMac.cpp, on_ack_timeout_timer_event().
if (_loramac.get_mcps_indication()->is_ack_recvd) {
tr_debug("Ack=OK, NbTrials=%d",
_loramac.get_mcps_confirmation()->nb_retries);
_loramac.post_process_mcps_req();
_ctrl_flags |= TX_DONE_FLAG;
_ctrl_flags &= ~TX_ONGOING_FLAG;
state_controller(DEVICE_STATE_STATUS_CHECK);
} else {
if (!_loramac.continue_sending_process() &&
_loramac.get_current_slot() != RX_SLOT_WIN_1) {
tr_error("Retries exhausted for Class A device");
_ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags |= TX_ONGOING_FLAG;
state_controller(DEVICE_STATE_STATUS_CHECK);
}
}
} else if (_loramac.get_device_class() == CLASS_A) {
// handle UNCONFIRMED case here, RX slots were turned off due to
// valid packet reception. For Class C, an outgoing UNCONFIRMED message
// gets its handling in process_transmission.
_loramac.post_process_mcps_req();
_ctrl_flags |= TX_DONE_FLAG;
state_controller(DEVICE_STATE_STATUS_CHECK);
}
// handle any pending MCPS indication // handle any pending MCPS indication
if (_loramac.get_mcps_indication()->pending) { if (_loramac.get_mcps_indication()->pending) {
@ -683,15 +728,13 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
state_controller(DEVICE_STATE_STATUS_CHECK); state_controller(DEVICE_STATE_STATUS_CHECK);
} }
// change the state only if a TX cycle completes for Class A // complete the cycle only if TX_DONE_FLAG is set
// For class C it's not needed as it will already be in receiving if (_ctrl_flags & TX_DONE_FLAG) {
// state, no matter if the TX cycle completed or not.
if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
// we are done here, update the state
state_machine_run_to_completion(); state_machine_run_to_completion();
} }
if (_loramac.get_mlme_indication()->pending) { // suppress auto uplink if another auto-uplink is in AWAITING_ACK state
if (_loramac.get_mlme_indication()->pending && !_automatic_uplink_ongoing) {
tr_debug("MLME Indication pending"); tr_debug("MLME Indication pending");
_loramac.post_process_mlme_ind(); _loramac.post_process_mlme_ind();
tr_debug("Immediate Uplink requested"); tr_debug("Immediate Uplink requested");
@ -727,18 +770,7 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
* never occurs. * never occurs.
*/ */
if (slot == RX_SLOT_WIN_2) { if (slot == RX_SLOT_WIN_2) {
_loramac.post_process_mcps_req(); post_process_tx_no_reception();
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
if (_loramac.continue_sending_process()) {
return;
} else {
tr_error("Retries exhausted for Class A device");
}
}
state_controller(DEVICE_STATE_STATUS_CHECK);
state_machine_run_to_completion();
} }
} }
@ -1027,11 +1059,15 @@ void LoRaWANStack::mcps_indication_handler()
|| (_loramac.get_device_class() == CLASS_C || (_loramac.get_device_class() == CLASS_C
&& mcps_indication->type == MCPS_CONFIRMED)) { && mcps_indication->type == MCPS_CONFIRMED)) {
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE) #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
tr_debug("Sending empty uplink message..."); // Do not queue an automatic uplink of there is one already outgoing
_automatic_uplink_ongoing = true; // This means we have not received an ack for the previous automatic uplink
const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port); if (!_automatic_uplink_ongoing) {
MBED_ASSERT(ret != 0); tr_debug("Sending empty uplink message...");
(void)ret; _automatic_uplink_ongoing = true;
const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port);
MBED_ASSERT(ret != 0);
(void)ret;
}
#else #else
send_event_to_application(UPLINK_REQUIRED); send_event_to_application(UPLINK_REQUIRED);
#endif #endif
@ -1085,8 +1121,7 @@ void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status)
_lw_session.active = false; _lw_session.active = false;
_device_current_state = DEVICE_STATE_SHUTDOWN; _device_current_state = DEVICE_STATE_SHUTDOWN;
op_status = LORAWAN_STATUS_DEVICE_OFF; op_status = LORAWAN_STATUS_DEVICE_OFF;
_ctrl_flags &= ~CONNECTED_FLAG; _ctrl_flags = 0;
_ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
send_event_to_application(DISCONNECTED); send_event_to_application(DISCONNECTED);
} }
@ -1102,20 +1137,15 @@ void LoRaWANStack::process_status_check_state()
// Another possibility is the case when the stack fails to schedule a // Another possibility is the case when the stack fails to schedule a
// deferred transmission and a scheduling failure handler is invoked. // deferred transmission and a scheduling failure handler is invoked.
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~TX_ONGOING_FLAG;
_loramac.set_tx_ongoing(false); _loramac.set_tx_ongoing(false);
_loramac.reset_ongoing_tx(); _loramac.reset_ongoing_tx();
mcps_confirm_handler(); mcps_confirm_handler();
} else if (_device_current_state == DEVICE_STATE_RECEIVING) { } else if (_device_current_state == DEVICE_STATE_RECEIVING) {
if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) { if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) {
// for CONFIRMED case, ack validity is already checked
// If it was a successful transmission, TX_ONGOING_FLAG will not be set.
// If it was indeed set, that means the device was in Class C mode and
// CONFIRMED transmission was in place and the ack retries maxed out.
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~TX_ONGOING_FLAG; _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
_loramac.set_tx_ongoing(false); _loramac.set_tx_ongoing(false);
_loramac.reset_ongoing_tx(); _loramac.reset_ongoing_tx();
// if an automatic uplink is ongoing, we should not send a TX_DONE // if an automatic uplink is ongoing, we should not send a TX_DONE
@ -1147,7 +1177,6 @@ void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status)
op_status = _loramac.send_ongoing_tx(); op_status = _loramac.send_ongoing_tx();
if (op_status == LORAWAN_STATUS_OK) { if (op_status == LORAWAN_STATUS_OK) {
_ctrl_flags |= TX_ONGOING_FLAG;
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
_loramac.set_tx_ongoing(true); _loramac.set_tx_ongoing(true);
_device_current_state = DEVICE_STATE_SENDING; _device_current_state = DEVICE_STATE_SENDING;

View File

@ -483,9 +483,11 @@ private:
void make_tx_metadata_available(void); void make_tx_metadata_available(void);
void make_rx_metadata_available(void); void make_rx_metadata_available(void);
void handle_ack_expiry_for_class_c(void);
void handle_scheduling_failure(void); void handle_scheduling_failure(void);
void post_process_tx_with_reception(void);
void post_process_tx_no_reception(void);
private: private:
LoRaMac _loramac; LoRaMac _loramac;
radio_events_t radio_events; radio_events_t radio_events;
@ -497,6 +499,7 @@ private:
lorawan_tx_metadata _tx_metadata; lorawan_tx_metadata _tx_metadata;
lorawan_rx_metadata _rx_metadata; lorawan_rx_metadata _rx_metadata;
uint8_t _num_retry; uint8_t _num_retry;
uint8_t _qos_cnt;
uint32_t _ctrl_flags; uint32_t _ctrl_flags;
uint8_t _app_port; uint8_t _app_port;
bool _link_check_requested; bool _link_check_requested;

View File

@ -79,7 +79,8 @@ LoRaMac::LoRaMac()
_is_nwk_joined(false), _is_nwk_joined(false),
_can_cancel_tx(true), _can_cancel_tx(true),
_continuous_rx2_window_open(false), _continuous_rx2_window_open(false),
_device_class(CLASS_A) _device_class(CLASS_A),
_prev_qos_level(LORAWAN_DEFAULT_QOS)
{ {
_params.keys.dev_eui = NULL; _params.keys.dev_eui = NULL;
_params.keys.app_eui = NULL; _params.keys.app_eui = NULL;
@ -174,6 +175,9 @@ void LoRaMac::post_process_mcps_req()
if (_params.is_ul_frame_counter_fixed == false) { if (_params.is_ul_frame_counter_fixed == false) {
_params.ul_frame_counter++; _params.ul_frame_counter++;
_params.adr_ack_counter++; _params.adr_ack_counter++;
if (_params.sys_params.nb_trans > 1) {
_mcps_confirmation.nb_retries = _params.ul_nb_rep_counter;
}
} }
} }
} }
@ -515,10 +519,6 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
return; return;
} }
// message is intended for us and MIC have passed, stop RX2 Window
// Spec: 3.3.4 Receiver Activity during the receive windows
_lora_time.stop(_params.timers.rx_window2_timer);
_mcps_confirmation.ack_received = false; _mcps_confirmation.ack_received = false;
_mcps_indication.is_ack_recvd = false; _mcps_indication.is_ack_recvd = false;
_mcps_indication.pending = true; _mcps_indication.pending = true;
@ -568,6 +568,8 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
tr_debug("Discarding duplicate frame"); tr_debug("Discarding duplicate frame");
_mcps_indication.pending = false; _mcps_indication.pending = false;
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
return;
} }
} else if (msg_type == FRAME_TYPE_DATA_UNCONFIRMED_DOWN) { } else if (msg_type == FRAME_TYPE_DATA_UNCONFIRMED_DOWN) {
_params.is_srv_ack_requested = false; _params.is_srv_ack_requested = false;
@ -585,6 +587,19 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
_params.dl_frame_counter = downlink_counter; _params.dl_frame_counter = downlink_counter;
} }
// message is intended for us and MIC have passed, stop RX2 Window
// Spec: 3.3.4 Receiver Activity during the receive windows
if (get_current_slot() == RX_SLOT_WIN_1) {
_lora_time.stop(_params.timers.rx_window2_timer);
} else {
_lora_time.stop(_params.timers.rx_window1_timer);
_lora_time.stop(_params.timers.rx_window2_timer);
}
if (_device_class == CLASS_C) {
_lora_time.stop(_rx2_closure_timer_for_class_c);
}
if (_params.is_node_ack_requested && fctrl.bits.ack) { if (_params.is_node_ack_requested && fctrl.bits.ack) {
_mcps_confirmation.ack_received = fctrl.bits.ack; _mcps_confirmation.ack_received = fctrl.bits.ack;
_mcps_indication.is_ack_recvd = fctrl.bits.ack; _mcps_indication.is_ack_recvd = fctrl.bits.ack;
@ -630,17 +645,32 @@ void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp)
_lora_phy->put_radio_to_sleep(); _lora_phy->put_radio_to_sleep();
} }
if ((_mcps_confirmation.req_type == MCPS_UNCONFIRMED)
&& (_params.sys_params.nb_trans > 1)) {
_params.ul_nb_rep_counter++;
MBED_ASSERT(_params.ul_nb_rep_counter <= _params.sys_params.nb_trans);
}
if (_params.is_rx_window_enabled == true) { if (_params.is_rx_window_enabled == true) {
lorawan_time_t time_diff = _lora_time.get_current_time() - timestamp; lorawan_time_t time_diff = _lora_time.get_current_time() - timestamp;
// start timer after which rx1_window will get opened // start timer after which rx1_window will get opened
_lora_time.start(_params.timers.rx_window1_timer, _lora_time.start(_params.timers.rx_window1_timer,
_params.rx_window1_delay - time_diff); _params.rx_window1_delay - time_diff);
if (_device_class != CLASS_C) { // start timer after which rx2_window will get opened
_lora_time.start(_params.timers.rx_window2_timer, _lora_time.start(_params.timers.rx_window2_timer,
_params.rx_window2_delay - time_diff); _params.rx_window2_delay - time_diff);
// If class C and an Unconfirmed messgae is outgoing,
// this will start a timer which will invoke rx2 would be
// closure handler
if (get_device_class() == CLASS_C) {
_lora_time.start(_rx2_closure_timer_for_class_c,
(_params.rx_window2_delay - time_diff) +
_params.rx_window2_config.window_timeout);
} }
// start timer after which ack wait will timeout (for Confirmed messages)
if (_params.is_node_ack_requested) { if (_params.is_node_ack_requested) {
_lora_time.start(_params.timers.ack_timeout_timer, _lora_time.start(_params.timers.ack_timeout_timer,
(_params.rx_window2_delay - time_diff) + (_params.rx_window2_delay - time_diff) +
@ -664,6 +694,7 @@ void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
int16_t rssi, int8_t snr) int16_t rssi, int8_t snr)
{ {
if (_device_class == CLASS_C && !_continuous_rx2_window_open) { if (_device_class == CLASS_C && !_continuous_rx2_window_open) {
_lora_time.stop(_rx2_closure_timer_for_class_c);
open_rx2_window(); open_rx2_window();
} else if (_device_class != CLASS_C){ } else if (_device_class != CLASS_C){
_lora_time.stop(_params.timers.rx_window1_timer); _lora_time.stop(_params.timers.rx_window1_timer);
@ -705,6 +736,7 @@ void LoRaMac::on_radio_tx_timeout(void)
{ {
_lora_time.stop(_params.timers.rx_window1_timer); _lora_time.stop(_params.timers.rx_window1_timer);
_lora_time.stop(_params.timers.rx_window2_timer); _lora_time.stop(_params.timers.rx_window2_timer);
_lora_time.stop(_rx2_closure_timer_for_class_c);
_lora_time.stop(_params.timers.ack_timeout_timer); _lora_time.stop(_params.timers.ack_timeout_timer);
if (_device_class == CLASS_C) { if (_device_class == CLASS_C) {
@ -718,16 +750,19 @@ void LoRaMac::on_radio_tx_timeout(void)
_mac_commands.clear_command_buffer(); _mac_commands.clear_command_buffer();
_mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; if (_mcps_confirmation.req_type == MCPS_CONFIRMED) {
_mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter;
} else {
_mcps_confirmation.nb_retries = _params.ul_nb_rep_counter;
}
_mcps_confirmation.ack_received = false; _mcps_confirmation.ack_received = false;
_mcps_confirmation.tx_toa = 0; _mcps_confirmation.tx_toa = 0;
} }
void LoRaMac::on_radio_rx_timeout(bool is_timeout) void LoRaMac::on_radio_rx_timeout(bool is_timeout)
{ {
if (_device_class == CLASS_C && !_continuous_rx2_window_open) { if (_device_class == CLASS_A) {
open_rx2_window();
} else {
_lora_phy->put_radio_to_sleep(); _lora_phy->put_radio_to_sleep();
} }
@ -869,7 +904,7 @@ void LoRaMac::open_rx1_window(void)
_lora_phy->rx_config(&_params.rx_window1_config); _lora_phy->rx_config(&_params.rx_window1_config);
_lora_phy->handle_receive(); _lora_phy->handle_receive();
tr_debug("Opening RX1 Window"); tr_debug("RX1 slot open, Freq = %lu", _params.rx_window1_config.frequency);
} }
void LoRaMac::open_rx2_window() void LoRaMac::open_rx2_window()
@ -898,7 +933,7 @@ void LoRaMac::open_rx2_window()
_lora_phy->handle_receive(); _lora_phy->handle_receive();
_params.rx_slot = _params.rx_window2_config.rx_slot; _params.rx_slot = _params.rx_window2_config.rx_slot;
tr_debug("Opening RX2 Window, Frequency = %lu", _params.rx_window2_config.frequency); tr_debug("RX2 slot open, Freq = %lu", _params.rx_window2_config.frequency);
} }
void LoRaMac::on_ack_timeout_timer_event(void) void LoRaMac::on_ack_timeout_timer_event(void)
@ -906,12 +941,6 @@ void LoRaMac::on_ack_timeout_timer_event(void)
Lock lock(*this); Lock lock(*this);
if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { 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; return;
} }
@ -1289,7 +1318,7 @@ int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port,
if (flags & MSG_PROPRIETARY_FLAG) { if (flags & MSG_PROPRIETARY_FLAG) {
_ongoing_tx_msg.type = MCPS_PROPRIETARY; _ongoing_tx_msg.type = MCPS_PROPRIETARY;
_ongoing_tx_msg.fport = port; _ongoing_tx_msg.fport = port;
_ongoing_tx_msg.nb_trials = 1; _ongoing_tx_msg.nb_trials = _params.sys_params.nb_trans;
// a proprietary frame only includes an MHDR field which contains MTYPE field. // a proprietary frame only includes an MHDR field which contains MTYPE field.
// Everything else is at the discretion of the implementer // Everything else is at the discretion of the implementer
fopts_len = 0; fopts_len = 0;
@ -1374,10 +1403,12 @@ device_class_t LoRaMac::get_device_class() const
} }
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) mbed::Callback<void(void)>rx2_would_be_closure_handler)
{ {
_device_class = device_class; _device_class = device_class;
_ack_expiry_handler_for_class_c = ack_expiry_handler; _rx2_would_be_closure_for_class_c = rx2_would_be_closure_handler;
_lora_time.init(_rx2_closure_timer_for_class_c, _rx2_would_be_closure_for_class_c);
if (CLASS_A == _device_class) { if (CLASS_A == _device_class) {
tr_debug("Changing device class to -> CLASS_A"); tr_debug("Changing device class to -> CLASS_A");
@ -1738,6 +1769,8 @@ lorawan_status_t LoRaMac::initialize(EventQueue *queue,
_ev_queue = queue; _ev_queue = queue;
_scheduling_failure_handler = scheduling_failure_handler; _scheduling_failure_handler = scheduling_failure_handler;
_rx2_closure_timer_for_class_c.callback = NULL;
_rx2_closure_timer_for_class_c.timer_id = -1;
_channel_plan.activate_channelplan_subsystem(_lora_phy); _channel_plan.activate_channelplan_subsystem(_lora_phy);
@ -1751,7 +1784,7 @@ lorawan_status_t LoRaMac::initialize(EventQueue *queue,
_params.timers.aggregated_timeoff = 0; _params.timers.aggregated_timeoff = 0;
_lora_phy->reset_to_default_values(&_params, true); _lora_phy->reset_to_default_values(&_params, true);
_params.sys_params.retry_num = 1; _params.sys_params.nb_trans = 1;
reset_mac_parameters(); reset_mac_parameters();
@ -1823,7 +1856,6 @@ uint8_t LoRaMac::get_max_possible_tx_size(uint8_t fopts_len)
max_possible_payload_size = allowed_frm_payload_size - fopts_len; max_possible_payload_size = allowed_frm_payload_size - fopts_len;
} else { } else {
max_possible_payload_size = allowed_frm_payload_size; max_possible_payload_size = allowed_frm_payload_size;
fopts_len = 0;
_mac_commands.clear_command_buffer(); _mac_commands.clear_command_buffer();
_mac_commands.clear_repeat_buffer(); _mac_commands.clear_repeat_buffer();
} }
@ -1931,3 +1963,18 @@ void LoRaMac::bind_phy(LoRaPHY &phy)
{ {
_lora_phy = &phy; _lora_phy = &phy;
} }
uint8_t LoRaMac::get_QOS_level()
{
if (_prev_qos_level != _params.sys_params.nb_trans) {
_prev_qos_level = _params.sys_params.nb_trans;
}
return _params.sys_params.nb_trans;
}
uint8_t LoRaMac::get_prev_QOS_level()
{
return _prev_qos_level;
}

View File

@ -295,10 +295,11 @@ public:
/** /**
* @brief set_device_class Sets active device class. * @brief set_device_class Sets active device class.
* @param device_class Device class to use. * @param device_class Device class to use.
* @param ack_expiry_handler callback function to inform about ack expiry * @param rx2_would_be_closure_handler callback function to inform about
* would be closure of RX2 window
*/ */
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); mbed::Callback<void(void)>rx2_would_be_closure_handler);
/** /**
* @brief setup_link_check_request Adds link check request command * @brief setup_link_check_request Adds link check request command
@ -404,6 +405,17 @@ public:
*/ */
rx_slot_t get_current_slot(void); rx_slot_t get_current_slot(void);
/**
* Indicates what level of QOS is set by network server. QOS level is set
* in response to a LinkADRReq for UNCONFIRMED messages
*/
uint8_t get_QOS_level(void);
/**
*Indicates level of QOS used for the previous outgoing message
*/
uint8_t get_prev_QOS_level(void);
/** /**
* These locks trample through to the upper layers and make * These locks trample through to the upper layers and make
* the stack thread safe. * the stack thread safe.
@ -632,10 +644,16 @@ private:
/** /**
* Class C doesn't timeout in RX2 window as it is a continuous window. * 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 * We use this callback to inform the LoRaWANStack controller that we did
* system cannot do more retries. * not receive a downlink in a time equal to normal Class A type RX2
* window timeout. This marks a 'would-be' closure for RX2, actual RX2 is
* not closed. Mostly network servers will send right at the beginning of
* RX2 window if they have something to send. So if we didn't receive anything
* in the time period equal to would be RX2 delay (which is a function of
* uplink message length and data rate), we will invoke this callback to let
* the upper layer know.
*/ */
mbed::Callback<void(void)> _ack_expiry_handler_for_class_c; mbed::Callback<void(void)> _rx2_would_be_closure_for_class_c;
/** /**
* Transmission is async, i.e., a call to schedule_tx() may be deferred to * Transmission is async, i.e., a call to schedule_tx() may be deferred to
@ -645,6 +663,8 @@ private:
*/ */
mbed::Callback<void(void)> _scheduling_failure_handler; mbed::Callback<void(void)> _scheduling_failure_handler;
timer_event_t _rx2_closure_timer_for_class_c;
/** /**
* Structure to hold MCPS indication data. * Structure to hold MCPS indication data.
*/ */
@ -674,6 +694,8 @@ private:
bool _continuous_rx2_window_open; bool _continuous_rx2_window_open;
device_class_t _device_class; device_class_t _device_class;
uint8_t _prev_qos_level;
}; };
#endif // MBED_LORAWAN_MAC_H__ #endif // MBED_LORAWAN_MAC_H__

View File

@ -145,40 +145,40 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
mlme_conf.nb_gateways = payload[mac_index++]; mlme_conf.nb_gateways = payload[mac_index++];
break; break;
case SRV_MAC_LINK_ADR_REQ: { case SRV_MAC_LINK_ADR_REQ: {
adr_req_params_t linkAdrReq; adr_req_params_t link_adr_req;
int8_t linkAdrDatarate = DR_0; int8_t link_adr_dr = DR_0;
int8_t linkAdrTxPower = TX_POWER_0; int8_t link_adr_txpower = TX_POWER_0;
uint8_t linkAdrNbRep = 0; uint8_t link_adr_nbtrans = 0;
uint8_t linkAdrNbBytesParsed = 0; uint8_t link_adr_nb_bytes_pasred = 0;
// Fill parameter structure // Fill parameter structure
linkAdrReq.payload = &payload[mac_index - 1]; link_adr_req.payload = &payload[mac_index - 1];
linkAdrReq.payload_size = commands_size - (mac_index - 1); link_adr_req.payload_size = commands_size - (mac_index - 1);
linkAdrReq.adr_enabled = mac_sys_params.adr_on; link_adr_req.adr_enabled = mac_sys_params.adr_on;
linkAdrReq.ul_dwell_time = mac_sys_params.uplink_dwell_time; link_adr_req.ul_dwell_time = mac_sys_params.uplink_dwell_time;
linkAdrReq.current_datarate = mac_sys_params.channel_data_rate; link_adr_req.current_datarate = mac_sys_params.channel_data_rate;
linkAdrReq.current_tx_power = mac_sys_params.channel_tx_power; link_adr_req.current_tx_power = mac_sys_params.channel_tx_power;
linkAdrReq.current_nb_rep = mac_sys_params.retry_num; link_adr_req.current_nb_trans = mac_sys_params.nb_trans;
// Process the ADR requests // Process the ADR requests
status = lora_phy.link_ADR_request(&linkAdrReq, status = lora_phy.link_ADR_request(&link_adr_req,
&linkAdrDatarate, &link_adr_dr,
&linkAdrTxPower, &link_adr_txpower,
&linkAdrNbRep, &link_adr_nbtrans,
&linkAdrNbBytesParsed); &link_adr_nb_bytes_pasred);
if ((status & 0x07) == 0x07) { if ((status & 0x07) == 0x07) {
mac_sys_params.channel_data_rate = linkAdrDatarate; mac_sys_params.channel_data_rate = link_adr_dr;
mac_sys_params.channel_tx_power = linkAdrTxPower; mac_sys_params.channel_tx_power = link_adr_txpower;
mac_sys_params.retry_num = linkAdrNbRep; mac_sys_params.nb_trans = link_adr_nbtrans;
} }
// Add the answers to the buffer // Add the answers to the buffer
for (uint8_t i = 0; i < (linkAdrNbBytesParsed / 5); i++) { for (uint8_t i = 0; i < (link_adr_nb_bytes_pasred / 5); i++) {
ret_value = add_link_adr_ans(status); ret_value = add_link_adr_ans(status);
} }
// Update MAC index // Update MAC index
mac_index += linkAdrNbBytesParsed - 1; mac_index += link_adr_nb_bytes_pasred - 1;
} }
break; break;
case SRV_MAC_DUTY_CYCLE_REQ: case SRV_MAC_DUTY_CYCLE_REQ:

View File

@ -36,7 +36,8 @@ SPDX-License-Identifier: BSD-3-Clause
#define CHANNELS_IN_MASK 16 #define CHANNELS_IN_MASK 16
LoRaPHY::LoRaPHY() LoRaPHY::LoRaPHY()
: _radio(NULL) : _radio(NULL),
_lora_time(NULL)
{ {
memset(&phy_params, 0, sizeof(phy_params)); memset(&phy_params, 0, sizeof(phy_params));
} }
@ -806,6 +807,11 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols,
((uint32_t *)phy_params.bandwidths.table)[rx_conf_params->datarate]); ((uint32_t *)phy_params.bandwidths.table)[rx_conf_params->datarate]);
} }
if (rx_conf_params->rx_slot == RX_SLOT_WIN_1) {
rx_conf_params->frequency = phy_params.channels.channel_list[rx_conf_params->channel].frequency;
}
get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME, get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME,
&rx_conf_params->window_timeout, &rx_conf_params->window_offset); &rx_conf_params->window_timeout, &rx_conf_params->window_offset);
} }
@ -988,7 +994,7 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t *link_adr_req,
verify_params.adr_enabled = link_adr_req->adr_enabled; verify_params.adr_enabled = link_adr_req->adr_enabled;
verify_params.current_datarate = link_adr_req->current_datarate; verify_params.current_datarate = link_adr_req->current_datarate;
verify_params.current_tx_power = link_adr_req->current_tx_power; verify_params.current_tx_power = link_adr_req->current_tx_power;
verify_params.current_nb_rep = link_adr_req->current_nb_rep; verify_params.current_nb_rep = link_adr_req->current_nb_trans;
verify_params.datarate = adr_settings.datarate; verify_params.datarate = adr_settings.datarate;
verify_params.tx_power = adr_settings.tx_power; verify_params.tx_power = adr_settings.tx_power;

View File

@ -479,7 +479,7 @@ uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t* params,
verify_params.nb_rep = adr_settings.nb_rep; verify_params.nb_rep = adr_settings.nb_rep;
verify_params.current_datarate = params->current_datarate; verify_params.current_datarate = params->current_datarate;
verify_params.current_tx_power = params->current_tx_power; verify_params.current_tx_power = params->current_tx_power;
verify_params.current_nb_rep = params->current_nb_rep; verify_params.current_nb_rep = params->current_nb_trans;
verify_params.channel_mask = temp_channel_masks; verify_params.channel_mask = temp_channel_masks;

View File

@ -510,7 +510,7 @@ uint8_t LoRaPHYCN470::link_ADR_request(adr_req_params_t* params,
verify_params.nb_rep = adr_settings.nb_rep; verify_params.nb_rep = adr_settings.nb_rep;
verify_params.current_datarate = params->current_datarate; verify_params.current_datarate = params->current_datarate;
verify_params.current_tx_power = params->current_tx_power; verify_params.current_tx_power = params->current_tx_power;
verify_params.current_nb_rep = params->current_nb_rep; verify_params.current_nb_rep = params->current_nb_trans;
verify_params.channel_mask = temp_channel_masks; verify_params.channel_mask = temp_channel_masks;

View File

@ -517,7 +517,7 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params,
verify_params.nb_rep = adr_settings.nb_rep; verify_params.nb_rep = adr_settings.nb_rep;
verify_params.current_datarate = params->current_datarate; verify_params.current_datarate = params->current_datarate;
verify_params.current_tx_power = params->current_tx_power; verify_params.current_tx_power = params->current_tx_power;
verify_params.current_nb_rep = params->current_nb_rep; verify_params.current_nb_rep = params->current_nb_trans;
verify_params.channel_mask = temp_channel_masks; verify_params.channel_mask = temp_channel_masks;
// Verify the parameters and update, if necessary // Verify the parameters and update, if necessary

View File

@ -329,9 +329,10 @@ typedef struct {
*/ */
int8_t current_tx_power; int8_t current_tx_power;
/*! /*!
* The current number of repetitions. * The current number of repetitions for obtaining a QOS level set by
* NS (applicable only to unconfirmed messages).
*/ */
uint8_t current_nb_rep; uint8_t current_nb_trans;
} adr_req_params_t; } adr_req_params_t;
/** /**

View File

@ -70,6 +70,8 @@ typedef uint32_t lorawan_time_t;
*/ */
#define LORAMAC_PHY_MAXPAYLOAD 255 #define LORAMAC_PHY_MAXPAYLOAD 255
#define LORAWAN_DEFAULT_QOS 1
/** /**
* *
* Default user application maximum data size for transmission * Default user application maximum data size for transmission
@ -187,9 +189,10 @@ typedef struct {
*/ */
uint32_t join_accept_delay2; uint32_t join_accept_delay2;
/*! /*!
* The number of uplink messages repetitions (confirmed messages only). * The number of uplink messages repetitions for QOS set by network server
* in LinkADRReq mac command (unconfirmed messages only).
*/ */
uint8_t retry_num; uint8_t nb_trans;
/*! /*!
* The datarate offset between uplink and downlink on first window. * The datarate offset between uplink and downlink on first window.
*/ */
@ -874,6 +877,9 @@ typedef struct {
*/ */
int8_t data_rate; int8_t data_rate;
/*! /*!
*
* For CONFIRMED Messages:
*
* The number of trials to transmit the frame, if the LoRaMAC layer did not * The number of trials to transmit the frame, if the LoRaMAC layer did not
* receive an acknowledgment. The MAC performs a datarate adaptation * receive an acknowledgment. The MAC performs a datarate adaptation
* according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in * according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in
@ -892,6 +898,13 @@ typedef struct {
* *
* Note that if nb_trials is set to 1 or 2, the MAC will not decrease * Note that if nb_trials is set to 1 or 2, the MAC will not decrease
* the datarate, if the LoRaMAC layer did not receive an acknowledgment. * the datarate, if the LoRaMAC layer did not receive an acknowledgment.
*
* For UNCONFIRMED Messages:
*
* Provides a certain QOS level set by network server in LinkADRReq MAC
* command. The device will transmit the given UNCONFIRMED message nb_trials
* time with same frame counter until a downlink is received. Standard defined
* range is 1:15. Data rates will NOT be adapted according to chapter 18.4.
*/ */
uint8_t nb_trials; uint8_t nb_trials;