diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellulardevice/unittest.cmake b/UNITTESTS/features/cellular/framework/AT/at_cellulardevice/unittest.cmake index a259abbaff..ca2c9c87be 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellulardevice/unittest.cmake +++ b/UNITTESTS/features/cellular/framework/AT/at_cellulardevice/unittest.cmake @@ -31,5 +31,5 @@ set(unittest-test-sources stubs/NetworkInterface_stub.cpp stubs/EventQueue_stub.cpp stubs/FileHandle_stub.cpp - stubs/mbed_assert_stub.cpp + stubs/mbed_assert_stub.c ) diff --git a/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp b/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp index 5f08cb0bd4..5bf5adeb7f 100644 --- a/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp +++ b/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp @@ -18,13 +18,79 @@ #include "gtest/gtest.h" #include "LoRaPHY.h" +#include "LoRaWANTimer_stub.h" class my_LoRaPHY : public LoRaPHY { public: - my_LoRaPHY(){}; + my_LoRaPHY(){phy_params.adr_ack_delay = 1;} - virtual ~my_LoRaPHY(){}; + virtual ~my_LoRaPHY(){} + + loraphy_params_t &get_phy_params() { + return phy_params; + } +}; + +class my_radio : public LoRaRadio +{ +public: + + virtual void init_radio(radio_events_t *events){}; + + virtual void radio_reset(){}; + + virtual void sleep(void){}; + + virtual void standby(void){}; + + virtual void set_rx_config (radio_modems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidth_afc, uint16_t preamble_len, + uint16_t symb_timeout, bool fix_len, + uint8_t payload_len, + bool crc_on, bool freq_hop_on, uint8_t hop_period, + bool iq_inverted, bool rx_continuous){}; + + virtual void set_tx_config(radio_modems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preamble_len, + bool fix_len, bool crc_on, bool freq_hop_on, + uint8_t hop_period, bool iq_inverted, uint32_t timeout){}; + + virtual void send(uint8_t *buffer, uint8_t size){}; + + virtual void receive(void){}; + + virtual void set_channel(uint32_t freq){}; + + virtual uint32_t random(void){}; + + virtual uint8_t get_status(void){return uint8_value;}; + + virtual void set_max_payload_length(radio_modems_t modem, uint8_t max){}; + + virtual void set_public_network(bool enable){}; + + virtual uint32_t time_on_air(radio_modems_t modem, uint8_t pkt_len){}; + + virtual bool perform_carrier_sense(radio_modems_t modem, + uint32_t freq, + int16_t rssi_threshold, + uint32_t max_carrier_sense_time){ return bool_value;}; + + virtual void start_cad(void){}; + + virtual bool check_rf_frequency(uint32_t frequency){ return bool_value; }; + + virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time){}; + + virtual void lock(void){}; + + virtual void unlock(void){}; + + bool bool_value; + uint8_t uint8_value; }; class Test_LoRaPHY : public testing::Test { @@ -42,8 +108,706 @@ protected: } }; -TEST_F(Test_LoRaPHY, constructor) +TEST_F(Test_LoRaPHY, initialize) { - EXPECT_TRUE(object); + object->initialize(NULL); } +TEST_F(Test_LoRaPHY, set_radio_instance) +{ + my_radio radio; + object->set_radio_instance(radio); +} + +TEST_F(Test_LoRaPHY, put_radio_to_sleep) +{ + my_radio radio; + object->set_radio_instance(radio); + object->put_radio_to_sleep(); +} + +TEST_F(Test_LoRaPHY, put_radio_to_standby) +{ + my_radio radio; + object->set_radio_instance(radio); + object->put_radio_to_standby(); +} + +TEST_F(Test_LoRaPHY, handle_receive) +{ + my_radio radio; + object->set_radio_instance(radio); + object->handle_receive(); +} + +TEST_F(Test_LoRaPHY, handle_send) +{ + my_radio radio; + object->set_radio_instance(radio); + object->handle_send(NULL, 0); +} + +TEST_F(Test_LoRaPHY, setup_public_network_mode) +{ + my_radio radio; + channel_params_t p; + object->get_phy_params().channels.channel_list = &p; + object->set_radio_instance(radio); + object->setup_public_network_mode(false); +} + +TEST_F(Test_LoRaPHY, get_radio_rng) +{ + my_radio radio; + object->set_radio_instance(radio); + EXPECT_TRUE(0 != object->get_radio_rng()); +} + +TEST_F(Test_LoRaPHY, calculate_backoff) +{ + channel_params_t p[1]; + p[0].band = 0; + object->get_phy_params().channels.channel_list = p; + band_t b[1]; + object->get_phy_params().bands.table = b; + object->calculate_backoff(false, false, false, 0, 10, 12); + + object->calculate_backoff(false, true, false, 0, 3600000 + 10, 12); + + object->calculate_backoff(false, false, true, 0, 3600000 + 36000000 + 10, 12); +} + +TEST_F(Test_LoRaPHY, mask_bit_test) +{ + uint16_t buf; + EXPECT_TRUE(!object->mask_bit_test(&buf, 0)); +} + +TEST_F(Test_LoRaPHY, mask_bit_set) +{ + uint16_t buf; + object->mask_bit_set(&buf, 3); +} + +TEST_F(Test_LoRaPHY, mask_bit_clear) +{ + uint16_t buf; + object->mask_bit_clear(&buf, 0); +} + +TEST_F(Test_LoRaPHY, request_new_channel) +{ + channel_params_t p; + EXPECT_TRUE(0 == object->request_new_channel(1, &p)); + + p.frequency = 0; + 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 + p.frequency = 2; + EXPECT_TRUE(0 == object->request_new_channel(1, &p)); + + //Freq & DR invalid + object->get_phy_params().max_channel_cnt = 2; + EXPECT_TRUE(0 == object->request_new_channel(1, &p)); + + //Freq invalid + pp.frequency = 0; + object->get_phy_params().default_max_datarate = 1; + 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; + EXPECT_TRUE(2 == object->request_new_channel(0, &p)); + + //DR invalid + pp.frequency = 2; + 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.min = 1; + EXPECT_TRUE(1 == object->request_new_channel(0, &p)); + + //STATUS_OK + p.dr_range.fields.max = 2; + uint16_t list2[16]; + p.dr_range.fields.min = 0; + object->get_phy_params().channels.mask = list2; + EXPECT_TRUE(3 == object->request_new_channel(0, &p)); +} + +TEST_F(Test_LoRaPHY, set_last_tx_done) +{ + channel_params_t p[1]; + p[0].band = 0; + object->get_phy_params().channels.channel_list = p; + band_t b[1]; + object->get_phy_params().bands.table = b; + object->set_last_tx_done(0, false, 0); + + object->set_last_tx_done(0, true, 0); +} + +TEST_F(Test_LoRaPHY, restore_default_channels) +{ + channel_params_t p[1]; + p[0].band = 0; + object->get_phy_params().channels.channel_list = p; + uint16_t m, dm; + object->get_phy_params().channels.mask_size = 1; + object->get_phy_params().channels.default_mask = &dm; + object->get_phy_params().channels.mask = &m; + object->restore_default_channels(); +} + +TEST_F(Test_LoRaPHY, apply_cf_list) +{ + uint8_t list[16]; + object->apply_cf_list(list, 0); + + object->get_phy_params().cflist_supported = true; + object->apply_cf_list(list, 0); + + object->get_phy_params().default_channel_cnt = 2; + object->get_phy_params().cflist_channel_cnt = 0; + object->get_phy_params().max_channel_cnt = 3; + + uint16_t mask[8]; + channel_params_t p[8]; + object->get_phy_params().channels.default_mask = mask; + object->get_phy_params().channels.mask = mask; + object->get_phy_params().channels.channel_list = p; + object->apply_cf_list(list, 16); + + list[1] = 15; + object->get_phy_params().cflist_channel_cnt = 1; + object->apply_cf_list(list, 16); +} + +TEST_F(Test_LoRaPHY, get_next_ADR) +{ + int8_t i = 0; + int8_t j = 0; + uint32_t ctr = 0; + object->get_phy_params().min_tx_datarate = 0; + EXPECT_TRUE(!object->get_next_ADR(false, i, j, ctr)); + + i = 1; + object->get_phy_params().adr_ack_limit = 3; + EXPECT_TRUE(!object->get_next_ADR(false, i, j, ctr)); + + object->get_phy_params().adr_ack_limit = 3; + ctr = 4; + object->get_phy_params().max_tx_power = 2; + object->get_phy_params().adr_ack_delay = 1; + EXPECT_TRUE(object->get_next_ADR(true, i, j, ctr)); + + ctr = 5; + object->get_phy_params().adr_ack_delay = 2; + EXPECT_TRUE(!object->get_next_ADR(true, i, j, ctr)); +} + +TEST_F(Test_LoRaPHY, rx_config) +{ + my_radio radio; + object->set_radio_instance(radio); + uint8_t list; + object->get_phy_params().datarates.table = &list; + uint8_t list2; + object->get_phy_params().payloads_with_repeater.table = &list2; + rx_config_params_t p; + p.datarate = 0; + p.rx_slot = RX_SLOT_WIN_1; + channel_params_t pp[1]; + object->get_phy_params().channels.channel_list = pp; + pp[0].rx1_frequency = 2; + p.channel = 0; + uint8_t tab[8]; + object->get_phy_params().payloads.table = tab; + object->get_phy_params().payloads_with_repeater.table = tab; + EXPECT_TRUE(object->rx_config(&p)); + + p.datarate = DR_7; + p.is_repeater_supported = true; + object->get_phy_params().fsk_supported = true; + EXPECT_TRUE(object->rx_config(&p)); +} + +TEST_F(Test_LoRaPHY, compute_rx_win_params) +{ + uint32_t list[1]; + list[0] = 0; + object->get_phy_params().bandwidths.table = list; + uint8_t list2; + object->get_phy_params().datarates.table = &list2; + rx_config_params_t p; + object->compute_rx_win_params(0, 0, 0, &p); + + p.datarate = 0; + list[0] = 125000; + object->compute_rx_win_params(0, 0, 0, &p); + + list[0] = 250000; + object->compute_rx_win_params(0, 0, 0, &p); + + list[0] = 500000; + object->get_phy_params().fsk_supported = true; + object->get_phy_params().max_rx_datarate = 0; + object->compute_rx_win_params(0, 0, 0, &p); +} + +TEST_F(Test_LoRaPHY, tx_config) +{ + band_t b; + object->get_phy_params().bands.table = &b; + channel_params_t pp; + pp.band=0; + object->get_phy_params().channels.channel_list = &pp; + uint32_t list = 0; + object->get_phy_params().bandwidths.table = &list; + uint8_t list2; + object->get_phy_params().datarates.table = &list2; + my_radio radio; + object->set_radio_instance(radio); + tx_config_params_t p; + p.channel=0; + int8_t i; + lorawan_time_t t; + object->tx_config(&p, &i, &t); + + p.datarate = 8; + object->get_phy_params().max_tx_datarate = 8; + object->tx_config(&p, &i, &t); +} + +TEST_F(Test_LoRaPHY, link_ADR_request) +{ + adr_req_params_t p; + uint8_t b[100]; + p.payload = b; + b[0] = 0x03; + b[1] = 1; + b[2] = 0; + b[3] = 0; + b[4] = 1 << 4; + b[5] = 0x03; + b[6] = 1; + b[7] = 1; + b[8] = 1; + b[9] = 6 << 4; + b[10] = 0x03; + b[11] = 1; + b[12] = 0xff; + b[13] = 0xff; + b[14] = 0; + b[15] = 0; + p.payload_size = 16; + int8_t i, j; + uint8_t k, l; + uint8_t t[5]; + t[0] = 0; + object->get_phy_params().datarates.size = 1; + object->get_phy_params().datarates.table = t; + //Test without ADR payload does not make sense here. + + object->get_phy_params().max_channel_cnt = 2; + channel_params_t li[4]; + object->get_phy_params().channels.channel_list = li; + li[0].frequency = 0; + li[1].frequency = 5; + EXPECT_TRUE(4 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + t[0] = 3; + //verify adr with p.adr_enabled = false + EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + p.current_nb_rep = 0; + EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + p.adr_enabled = true; + li[0].dr_range.value = 0xff; + object->get_phy_params().min_tx_datarate = DR_3; + object->get_phy_params().max_tx_datarate = DR_8; + + //verify adr with status != 0 + EXPECT_TRUE(0 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + object->get_phy_params().max_tx_power = 2; + object->get_phy_params().min_tx_power = 6; + //verify adr with status != 0 + EXPECT_TRUE(4 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + object->get_phy_params().min_tx_datarate = DR_0; + li[0].dr_range.value = 0xf0; + EXPECT_TRUE(6 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + li[1].dr_range.fields.min = DR_0; + li[1].dr_range.fields.max = DR_13; + b[4] = 6 << 4; + p.payload_size = 5; + EXPECT_TRUE(7 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + uint16_t mask[2]; + object->get_phy_params().channels.mask = mask; + object->get_phy_params().channels.mask_size = 2; + EXPECT_TRUE(7 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + li[0].dr_range.value = 0xff; + object->get_phy_params().max_channel_cnt = 0; + EXPECT_TRUE(5 == object->link_ADR_request(&p, &i, &j, &k, &l)); + + b[0] = 0x03; + b[1] = 1; + b[2] = 0; + b[3] = 0; + b[4] = 0; + t[0] = 0; + object->get_phy_params().datarates.size = 1; + object->get_phy_params().datarates.table = t; + //Test without ADR payload does not make sense here. + + object->get_phy_params().max_channel_cnt = 2; + li[0].frequency = 0; + li[1].frequency = 5; + EXPECT_TRUE(4 == object->link_ADR_request(&p, &i, &j, &k, &l)); +} + +TEST_F(Test_LoRaPHY, accept_rx_param_setup_req) +{ + my_radio radio; + object->set_radio_instance(radio); + rx_param_setup_req_t req; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&req)); +} + +TEST_F(Test_LoRaPHY, accept_tx_param_setup_req) +{ + my_radio radio; + object->set_radio_instance(radio); + object->get_phy_params().accept_tx_param_setup_req = true; + EXPECT_TRUE(object->accept_tx_param_setup_req(0, 0)); +} + +TEST_F(Test_LoRaPHY, dl_channel_request) +{ + EXPECT_TRUE(0 == object->dl_channel_request(0, 0)); + + object->get_phy_params().dl_channel_req_supported = true; + object->get_phy_params().bands.size = 1; + band_t t[1]; + object->get_phy_params().bands.table = t; + channel_params_t p[4]; + object->get_phy_params().channels.channel_list = p; + + p[0].frequency = 0; + EXPECT_TRUE(0 == object->dl_channel_request(0, 1)); + + t[0].higher_band_freq = 19; + t[0].lower_band_freq = 0; + p[0].frequency = 1; + EXPECT_TRUE(3 == object->dl_channel_request(0, 1)); +} + +TEST_F(Test_LoRaPHY, get_alternate_DR) +{ + EXPECT_TRUE(0 == object->get_alternate_DR(0)); + + object->get_phy_params().default_max_datarate = 5; + object->get_phy_params().min_tx_datarate = 4; + EXPECT_TRUE(5 == object->get_alternate_DR(1)); + + object->get_phy_params().default_max_datarate = 6; + object->get_phy_params().min_tx_datarate = 4; + EXPECT_TRUE(5 == object->get_alternate_DR(2)); +} + +TEST_F(Test_LoRaPHY, set_next_channel) +{ + channel_selection_params_t p; + uint8_t ch; + lorawan_time_t t1; + lorawan_time_t t2; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2)); + + uint16_t list[16]; + list[4] = 1; + memcpy(list, "\0", 16); + object->get_phy_params().channels.mask = list; + object->get_phy_params().channels.mask_size = 1; + p.aggregate_timeoff = 10000; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2)); + + LoRaWANTimer_stub::time_value = 20000; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&p, &ch, &t1, &t2)); + + p.joined = false; + p.dc_enabled = false; + band_t b[4]; + object->get_phy_params().bands.size = 2; + object->get_phy_params().bands.table = &b; + b[0].off_time = 0; + b[1].off_time = 9999999; + list[4] = 0; + object->get_phy_params().channels.mask_size = 128; + p.current_datarate = DR_1; + object->get_phy_params().max_channel_cnt = 4; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&p, &ch, &t1, &t2)); + + p.dc_enabled = true; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&p, &ch, &t1, &t2)); + + list[4] = 1; + p.joined = true; + p.dc_enabled = false; + channel_params_t l[4]; + l[0].dr_range.value = 0xff; + l[1].dr_range.value = 0xff; + l[2].dr_range.value = 0xf0; + l[3].dr_range.value = 0xf0; + l[2].band = 2; + l[3].band = 3; + object->get_phy_params().channels.channel_list = l; + list[0] = 0xFF; + b[2].off_time = 9999999; + b[3].off_time = 0; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&p, &ch, &t1, &t2)); + + b[0].off_time = 10000; + LoRaWANTimer_stub::time_value = 2000; + p.aggregate_timeoff = 1000; + p.dc_enabled = true; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&p, &ch, &t1, &t2)); +} + +TEST_F(Test_LoRaPHY, add_channel) +{ + uint16_t list[16]; + object->get_phy_params().channels.mask = list; + object->get_phy_params().channels.default_mask = list; + channel_params_t p; + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->add_channel(&p, 0)); + + object->get_phy_params().custom_channelplans_supported = true; + object->get_phy_params().max_channel_cnt = 2; + object->get_phy_params().min_tx_datarate = 0; + object->get_phy_params().max_tx_datarate = 13; + p.dr_range.fields.min = 6; + p.dr_range.fields.max = 1; + EXPECT_TRUE(LORAWAN_STATUS_FREQ_AND_DR_INVALID == object->add_channel(&p, 0)); +} + +TEST_F(Test_LoRaPHY, remove_channel) +{ + channel_params_t pp; + pp.band=0; + object->get_phy_params().channels.channel_list = &pp; + uint16_t list[16]; + list[0] = 1; + object->get_phy_params().channels.mask = list; + object->get_phy_params().channels.default_mask = list; + EXPECT_TRUE(false == object->remove_channel(0)); + + list[0] = 0; + EXPECT_TRUE(false == object->remove_channel(0)); + + object->get_phy_params().channels.mask_size = 1; + object->get_phy_params().max_channel_cnt = 0; + EXPECT_TRUE(false == object->remove_channel(0)); + + object->get_phy_params().max_channel_cnt = 1; + EXPECT_TRUE(true == object->remove_channel(0)); +} + +TEST_F(Test_LoRaPHY, set_tx_cont_mode) +{ + channel_params_t pp; + pp.band=0; + object->get_phy_params().channels.channel_list = &pp; + band_t b; + object->get_phy_params().bands.table = &b; + my_radio radio; + object->set_radio_instance(radio); + + cw_mode_params_t p; + p.max_eirp = 0; + p.channel=0; + object->set_tx_cont_mode(&p); + + p.max_eirp = 1; + p.antenna_gain = 1; + object->set_tx_cont_mode(&p, 1); +} + +TEST_F(Test_LoRaPHY, apply_DR_offset) +{ + EXPECT_TRUE(0 == object->apply_DR_offset(0, 0)); + + object->get_phy_params().min_tx_datarate = 1; + EXPECT_TRUE(1 == object->apply_DR_offset(0, 2)); +} + +TEST_F(Test_LoRaPHY, reset_to_default_values) +{ + loramac_protocol_params p; + object->reset_to_default_values(&p); + + object->reset_to_default_values(&p, true); +} + +TEST_F(Test_LoRaPHY, get_next_lower_tx_datarate) +{ + EXPECT_TRUE(DR_0 == object->get_next_lower_tx_datarate(DR_2)); + + object->get_phy_params().ul_dwell_time_setting = 1; + object->get_phy_params().dwell_limit_datarate = DR_1; + EXPECT_TRUE(DR_1 == object->get_next_lower_tx_datarate(DR_2)); +} + +TEST_F(Test_LoRaPHY, get_minimum_rx_datarate) +{ + EXPECT_TRUE(DR_0 == object->get_minimum_rx_datarate()); + + object->get_phy_params().dl_dwell_time_setting = 1; + object->get_phy_params().dwell_limit_datarate = DR_1; + EXPECT_TRUE(DR_1 == object->get_minimum_rx_datarate()); +} + +TEST_F(Test_LoRaPHY, get_minimum_tx_datarate) +{ + EXPECT_TRUE(DR_0 == object->get_minimum_tx_datarate()); + + object->get_phy_params().ul_dwell_time_setting = 1; + object->get_phy_params().dwell_limit_datarate = DR_1; + EXPECT_TRUE(DR_1 == object->get_minimum_tx_datarate()); +} + +TEST_F(Test_LoRaPHY, get_default_tx_datarate) +{ + EXPECT_TRUE(0 == object->get_default_tx_datarate()); +} + +TEST_F(Test_LoRaPHY, get_default_max_tx_datarate) +{ + EXPECT_TRUE(DR_0 == object->get_default_max_tx_datarate()); +} + +TEST_F(Test_LoRaPHY, get_default_tx_power) +{ + EXPECT_TRUE(0 == object->get_default_tx_power()); +} + +TEST_F(Test_LoRaPHY, get_max_payload) +{ + uint8_t list=8; + object->get_phy_params().payloads.table = &list; + object->get_phy_params().payloads_with_repeater.table = &list; + EXPECT_TRUE(8 == object->get_max_payload(0)); + + EXPECT_TRUE(8 == object->get_max_payload(0, true)); +} + +TEST_F(Test_LoRaPHY, get_maximum_frame_counter_gap) +{ + EXPECT_TRUE(0 == object->get_maximum_frame_counter_gap()); +} + +TEST_F(Test_LoRaPHY, get_ack_timeout) +{ + EXPECT_TRUE(0 == object->get_ack_timeout()); +} + +TEST_F(Test_LoRaPHY, get_default_rx2_frequency) +{ + EXPECT_TRUE(0 == object->get_default_rx2_frequency()); +} + +TEST_F(Test_LoRaPHY, get_default_rx2_datarate) +{ + EXPECT_TRUE(0 == object->get_default_rx2_datarate()); +} + +TEST_F(Test_LoRaPHY, get_channel_mask) +{ + EXPECT_TRUE(0 == object->get_channel_mask()); + EXPECT_TRUE(0 == object->get_channel_mask(true)); +} + +TEST_F(Test_LoRaPHY, get_max_nb_channels) +{ + EXPECT_TRUE(0 == object->get_max_nb_channels()); +} + +TEST_F(Test_LoRaPHY, get_phy_channels) +{ + EXPECT_TRUE(0 == object->get_phy_channels()); +} + +TEST_F(Test_LoRaPHY, is_custom_channel_plan_supported) +{ + EXPECT_TRUE(false == object->is_custom_channel_plan_supported()); +} + +TEST_F(Test_LoRaPHY, verify_rx_datarate) +{ + EXPECT_TRUE(false == object->verify_rx_datarate(0)); + + object->get_phy_params().datarates.size = 1; + uint8_t t[1]; + t[0] = 2; + object->get_phy_params().datarates.table = t; + object->get_phy_params().dl_dwell_time_setting = 0; + + EXPECT_TRUE(true == object->verify_rx_datarate(0)); + + object->get_phy_params().dl_dwell_time_setting = 1; + object->get_phy_params().min_rx_datarate = 0; + + EXPECT_TRUE(true == object->verify_rx_datarate(0)); +} + +TEST_F(Test_LoRaPHY, verify_tx_datarate) +{ + EXPECT_TRUE(false == object->verify_tx_datarate(0)); + + object->get_phy_params().datarates.size = 1; + uint8_t t[1]; + t[0] = 2; + object->get_phy_params().datarates.table = t; + object->get_phy_params().ul_dwell_time_setting = 0; + EXPECT_TRUE(true == object->verify_tx_datarate(0)); + + object->get_phy_params().ul_dwell_time_setting = 1; + EXPECT_TRUE(true == object->verify_tx_datarate(0)); + + object->get_phy_params().ul_dwell_time_setting = 1; + EXPECT_TRUE(true == object->verify_tx_datarate(0, true)); +} + +TEST_F(Test_LoRaPHY, verify_tx_power) +{ + EXPECT_TRUE(true == object->verify_tx_power(0)); +} + +TEST_F(Test_LoRaPHY, verify_duty_cycle) +{ + EXPECT_TRUE(true == object->verify_duty_cycle(false)); + + EXPECT_TRUE(false == object->verify_duty_cycle(true)); +} + +TEST_F(Test_LoRaPHY, verify_nb_join_trials) +{ + EXPECT_TRUE(false == object->verify_nb_join_trials(0)); + EXPECT_TRUE(true == object->verify_nb_join_trials(100)); +} + + diff --git a/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp b/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp index bc5cae491d..0cdde0f104 100644 --- a/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp +++ b/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp @@ -229,4 +229,3 @@ TEST_F(Test_LoRaPHYAU915, apply_DR_offset) } } } - diff --git a/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp b/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp index 899b47e058..4bd793f703 100644 --- a/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp +++ b/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp @@ -233,4 +233,3 @@ TEST_F(Test_LoRaPHYUS915, set_tx_cont_mode) p.datarate = 4; object->set_tx_cont_mode(&p, 0); } - diff --git a/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp b/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp index 4c4a5dffed..c3e7fbba87 100644 --- a/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp +++ b/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp @@ -17,6 +17,87 @@ #include "gtest/gtest.h" #include "LoRaWANStack.h" +#include "EventQueue.h" + +#include "LoRaPHY_stub.h" + +using namespace events; + +class my_LoRaPHY : public LoRaPHY +{ +public: + my_LoRaPHY(){}; + + virtual ~my_LoRaPHY(){}; +}; + +uint8_t my_cb() +{ + return 1; +} + +class my_radio : public LoRaRadio +{ +public: + + virtual void init_radio(radio_events_t *events){}; + + virtual void radio_reset(){}; + + virtual void sleep(void){}; + + virtual void standby(void){}; + + virtual void set_rx_config (radio_modems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidth_afc, uint16_t preamble_len, + uint16_t symb_timeout, bool fix_len, + uint8_t payload_len, + bool crc_on, bool freq_hop_on, uint8_t hop_period, + bool iq_inverted, bool rx_continuous){}; + + virtual void set_tx_config(radio_modems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preamble_len, + bool fix_len, bool crc_on, bool freq_hop_on, + uint8_t hop_period, bool iq_inverted, uint32_t timeout){}; + + virtual void send(uint8_t *buffer, uint8_t size){}; + + virtual void receive(void){}; + + virtual void set_channel(uint32_t freq){}; + + virtual uint32_t random(void){}; + + virtual uint8_t get_status(void){return uint8_value;}; + + virtual void set_max_payload_length(radio_modems_t modem, uint8_t max){}; + + virtual void set_public_network(bool enable){}; + + virtual uint32_t time_on_air(radio_modems_t modem, uint8_t pkt_len){}; + + virtual bool perform_carrier_sense(radio_modems_t modem, + uint32_t freq, + int16_t rssi_threshold, + uint32_t max_carrier_sense_time){ return bool_value;}; + + virtual void start_cad(void){}; + + virtual bool check_rf_frequency(uint32_t frequency){ return bool_value; }; + + virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time){}; + + virtual void lock(void){}; + + virtual void unlock(void){}; + + bool bool_value; + uint8_t uint8_value; +}; + + class Test_LoRaWANStack : public testing::Test { protected: @@ -38,3 +119,134 @@ TEST_F(Test_LoRaWANStack, constructor) EXPECT_TRUE(object); } +TEST_F(Test_LoRaWANStack, bind_phy_and_radio_driver) +{ + my_radio radio; + my_LoRaPHY phy; + object->bind_phy_and_radio_driver(radio, phy); +} + +TEST_F(Test_LoRaWANStack, initialize_mac_layer) +{ + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->initialize_mac_layer(NULL)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); +} + +TEST_F(Test_LoRaWANStack, set_lora_callbacks) +{ + lorawan_app_callbacks_t cb; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_lora_callbacks(&cb)); +} + +TEST_F(Test_LoRaWANStack, connect) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect()); + + lorawan_connect_t conn; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect(conn)); +} + +TEST_F(Test_LoRaWANStack, add_channels) +{ + lorawan_channelplan_t plan; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->add_channels(plan)); +} + +TEST_F(Test_LoRaWANStack, remove_a_channel) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->remove_a_channel(1)); +} + +TEST_F(Test_LoRaWANStack, drop_channel_list) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->drop_channel_list()); +} + +TEST_F(Test_LoRaWANStack, get_enabled_channels) +{ + lorawan_channelplan_t plan; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->get_enabled_channels(plan)); +} + +TEST_F(Test_LoRaWANStack, set_confirmed_msg_retry) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_confirmed_msg_retry(1)); +} + +TEST_F(Test_LoRaWANStack, set_channel_data_rate) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_channel_data_rate(4)); +} + +TEST_F(Test_LoRaWANStack, enable_adaptive_datarate) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->enable_adaptive_datarate(false)); +} + +TEST_F(Test_LoRaWANStack, handle_tx) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->handle_tx(0, NULL, 0, 0, true, false)); +} + +TEST_F(Test_LoRaWANStack, handle_rx) +{ + uint8_t port; + int flags; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->handle_rx(NULL, 0, port, flags, false)); +} + +TEST_F(Test_LoRaWANStack, set_link_check_request) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_link_check_request()); +} + +TEST_F(Test_LoRaWANStack, remove_link_check_request) +{ + object->remove_link_check_request(); +} + +TEST_F(Test_LoRaWANStack, shutdown) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->shutdown()); +} + +TEST_F(Test_LoRaWANStack, set_device_class) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_device_class(CLASS_A)); +} + +TEST_F(Test_LoRaWANStack, acquire_tx_metadata) +{ + lorawan_tx_metadata data; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_tx_metadata(data)); +} + +TEST_F(Test_LoRaWANStack, acquire_rx_metadata) +{ + lorawan_rx_metadata data; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_rx_metadata(data)); +} + +TEST_F(Test_LoRaWANStack, acquire_backoff_metadata) +{ + int b; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_backoff_metadata(b)); +} + +TEST_F(Test_LoRaWANStack, stop_sending) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->stop_sending()); +} + +TEST_F(Test_LoRaWANStack, lock) +{ + object->lock(); +} + +TEST_F(Test_LoRaWANStack, unlock) +{ + object->unlock(); +} + diff --git a/UNITTESTS/stubs/LoRaPHY_stub.cpp b/UNITTESTS/stubs/LoRaPHY_stub.cpp index cc00240aa3..978cf1dd0b 100644 --- a/UNITTESTS/stubs/LoRaPHY_stub.cpp +++ b/UNITTESTS/stubs/LoRaPHY_stub.cpp @@ -104,9 +104,7 @@ int32_t LoRaPHY::get_random(int32_t min, int32_t max) return LoRaPHY_stub::uint32_value; } -bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t *channel_mask, - int8_t dr, int8_t min_dr, int8_t max_dr, - channel_params_t *channels) +bool LoRaPHY::verify_channel_DR(uint16_t *channel_mask, int8_t dr) { return LoRaPHY_stub::bool_table[LoRaPHY_stub::bool_counter++]; } @@ -142,24 +140,6 @@ void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t } } -void LoRaPHY::intersect_channel_mask(const uint16_t *source, - uint16_t *destination, uint8_t size) -{ -} - -void LoRaPHY::fill_channel_mask_with_fsb(const uint16_t *expectation, - const uint16_t *fsb_mask, - uint16_t *destination, - uint8_t size) -{ - -} - -void LoRaPHY::fill_channel_mask_with_value(uint16_t *channel_mask, - uint16_t value, uint8_t size) -{ -} - void LoRaPHY::set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time) { } @@ -188,16 +168,6 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params, return LoRaPHY_stub::uint8_value; } -double LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth) -{ - return LoRaPHY_stub::double_value; -} - -double LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr) -{ - return LoRaPHY_stub::double_value; -} - void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb, uint32_t rx_error, uint32_t wakeup_time, uint32_t *window_timeout, int32_t *window_offset) diff --git a/UNITTESTS/stubs/LoRaWANTimer_stub.cpp b/UNITTESTS/stubs/LoRaWANTimer_stub.cpp index 1b7f88b135..0b7bcb1880 100644 --- a/UNITTESTS/stubs/LoRaWANTimer_stub.cpp +++ b/UNITTESTS/stubs/LoRaWANTimer_stub.cpp @@ -17,6 +17,10 @@ #include "LoRaWANTimer.h" +#include "LoRaWANTimer_stub.h" + +lorawan_time_t LoRaWANTimer_stub::time_value = 0; + LoRaWANTimeHandler::LoRaWANTimeHandler() : _queue(NULL) { @@ -32,12 +36,12 @@ void LoRaWANTimeHandler::activate_timer_subsystem(events::EventQueue *queue) lorawan_time_t LoRaWANTimeHandler::get_current_time( void ) { - return (lorawan_time_t)0; + return LoRaWANTimer_stub::time_value; } lorawan_time_t LoRaWANTimeHandler::get_elapsed_time(lorawan_time_t saved_time) { - return (lorawan_time_t)0; + return LoRaWANTimer_stub::time_value; } void LoRaWANTimeHandler::init(timer_event_t &obj, mbed::Callback callback) diff --git a/UNITTESTS/stubs/LoRaWANTimer_stub.h b/UNITTESTS/stubs/LoRaWANTimer_stub.h new file mode 100644 index 0000000000..b8d59a6fa5 --- /dev/null +++ b/UNITTESTS/stubs/LoRaWANTimer_stub.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LoRaWANTimer.h" + +namespace LoRaWANTimer_stub +{ +extern lorawan_time_t time_value; +} diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index 7a8462fa8e..6a6b5869b1 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -164,19 +164,18 @@ int32_t LoRaPHY::get_random(int32_t min, int32_t max) return (int32_t) rand() % (max - min + 1) + min; } -bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t *channel_mask, - int8_t dr, int8_t min_dr, int8_t max_dr, - channel_params_t *channels) +bool LoRaPHY::verify_channel_DR(uint16_t *channel_mask, int8_t dr) { - if (val_in_range(dr, min_dr, max_dr) == 0) { + if (val_in_range(dr, phy_params.min_tx_datarate, + phy_params.max_tx_datarate) == 0) { return false; } for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) { if (mask_bit_test(channel_mask, i)) { // Check datarate validity for enabled channels - if (val_in_range(dr, (channels[i].dr_range.fields.min & 0x0F), - (channels[i].dr_range.fields.max & 0x0F))) { + if (val_in_range(dr, (phy_params.channels.channel_list[i].dr_range.fields.min & 0x0F), + (phy_params.channels.channel_list[i].dr_range.fields.max & 0x0F))) { // At least 1 channel has been found we can return OK. return true; } @@ -248,45 +247,6 @@ void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t } } -void LoRaPHY::intersect_channel_mask(const uint16_t *source, - uint16_t *destination, uint8_t size) -{ - if (!source || !destination || size == 0) { - return; - } - - for (uint8_t i = 0; i < size; i++) { - destination[i] &= source[i]; - } -} - -void LoRaPHY::fill_channel_mask_with_fsb(const uint16_t *expectation, - const uint16_t *fsb_mask, - uint16_t *destination, - uint8_t size) -{ - if (!expectation || !fsb_mask || !destination || size == 0) { - return; - } - - for (uint8_t i = 0; i < size; i++) { - destination[i] = expectation[i] & fsb_mask[i]; - } - -} - -void LoRaPHY::fill_channel_mask_with_value(uint16_t *channel_mask, - uint16_t value, uint8_t size) -{ - if (!channel_mask || size == 0) { - return; - } - - for (uint8_t i = 0; i < size; i++) { - channel_mask[i] = value; - } -} - void LoRaPHY::set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time) { band_t *band_table = (band_t *) phy_params.bands.table; @@ -396,16 +356,13 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params, if (status != 0) { // Verify channel datarate - if (verify_channel_DR(phy_params.max_channel_cnt, verify_params->channel_mask, - datarate, phy_params.min_tx_datarate, - phy_params.max_tx_datarate, phy_params.channels.channel_list) - == false) { + if (verify_channel_DR(verify_params->channel_mask, datarate) == false) { status &= 0xFD; // Datarate KO } // Verify tx power if (val_in_range(tx_power, phy_params.max_tx_power, - phy_params.min_tx_power) == 0) { + phy_params.min_tx_power) == false) { // Verify if the maximum TX power is exceeded if (phy_params.max_tx_power > tx_power) { // Apply maximum TX power. Accept TX power. @@ -1140,8 +1097,8 @@ uint8_t LoRaPHY::dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency) uint8_t status = 0x03; // Verify if the frequency is supported - uint8_t band = lookup_band_for_frequency(rx1_frequency); - if (verify_frequency_for_band(rx1_frequency, band) == false) { + int band = lookup_band_for_frequency(rx1_frequency); + if (band < 0) { status &= 0xFE; } @@ -1343,7 +1300,7 @@ lorawan_status_t LoRaPHY::add_channel(const channel_params_t *new_channel, // Default channels don't accept all values if (id < phy_params.default_channel_cnt) { // Validate the datarate range for min: must be DR_0 - if (new_channel->dr_range.fields.min > phy_params.min_tx_datarate) { + if (new_channel->dr_range.fields.min != DR_0) { dr_invalid = true; } diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index 5b4ed32b8b..42c45b9575 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -535,26 +535,6 @@ public: //Verifiers protected: LoRaPHY(); - /** - * Sets the intersection of source and destination channel masks - * into the destination. - */ - void intersect_channel_mask(const uint16_t *source, uint16_t *destination, - uint8_t size); - - /** - * Fills channel mask array based upon the provided FSB mask - */ - void fill_channel_mask_with_fsb(const uint16_t *expectation, - const uint16_t *fsb_mask, - uint16_t *channel_mask, uint8_t size); - - /** - * Fills channel mask array with a given value - */ - void fill_channel_mask_with_value(uint16_t *channel_mask, - uint16_t value, uint8_t size); - /** * Looks up corresponding band for a frequency. Returns -1 if not in any band. */ @@ -573,8 +553,7 @@ protected: /** * Verifies, if a datarate is available on an active channel. */ - bool verify_channel_DR(uint8_t nbChannels, uint16_t* channelsMask, int8_t dr, - int8_t minDr, int8_t maxDr, channel_params_t* channels); + bool verify_channel_DR(uint16_t* channelsMask, int8_t dr); /** * Disables a channel in a given channels mask. @@ -615,16 +594,6 @@ protected: uint8_t verify_link_ADR_req(verify_adr_params_t* verify_params, int8_t* dr, int8_t* tx_pow, uint8_t* nb_rep); - /** - * Computes the symbol time for LoRa modulation. - */ - double compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth ); - - /** - * Computes the symbol time for FSK modulation. - */ - double compute_symb_timeout_fsk(uint8_t phy_dr); - /** * Computes the RX window timeout and the RX window offset. */ @@ -658,6 +627,18 @@ protected: bool is_datarate_supported(const int8_t datarate) const; +private: + + /** + * Computes the symbol time for LoRa modulation. + */ + double compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth ); + + /** + * Computes the symbol time for FSK modulation. + */ + double compute_symb_timeout_fsk(uint8_t phy_dr); + protected: LoRaRadio *_radio; LoRaWANTimeHandler *_lora_time; diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp index de79e51f29..97d80016f4 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp @@ -617,3 +617,30 @@ uint8_t LoRaPHYAU915::apply_DR_offset(int8_t dr, int8_t dr_offset) { return datarate_offsets_AU915[dr][dr_offset]; } + +void LoRaPHYAU915::intersect_channel_mask(const uint16_t *source, + uint16_t *destination, uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + destination[i] &= source[i]; + } +} + +void LoRaPHYAU915::fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *destination, + uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + destination[i] = expectation[i] & fsb_mask[i]; + } + +} + +void LoRaPHYAU915::fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + channel_mask[i] = value; + } +} diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.h b/features/lorawan/lorastack/phy/LoRaPHYAU915.h index 1db1ff227c..27add455d9 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.h +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.h @@ -76,6 +76,28 @@ public: virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); +private: + + /** + * Sets the intersection of source and destination channel masks + * into the destination. + */ + void intersect_channel_mask(const uint16_t *source, uint16_t *destination, + uint8_t size); + + /** + * Fills channel mask array based upon the provided FSB mask + */ + void fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *channel_mask, uint8_t size); + + /** + * Fills channel mask array with a given value + */ + void fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size); + private: /*! diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp index 0ea2ddd930..95d52d212d 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp @@ -678,3 +678,31 @@ uint8_t LoRaPHYUS915::apply_DR_offset(int8_t dr, int8_t dr_offset) { return datarate_offsets_US915[dr][dr_offset]; } + + +void LoRaPHYUS915::intersect_channel_mask(const uint16_t *source, + uint16_t *destination, uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + destination[i] &= source[i]; + } +} + +void LoRaPHYUS915::fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *destination, + uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + destination[i] = expectation[i] & fsb_mask[i]; + } + +} + +void LoRaPHYUS915::fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) { + channel_mask[i] = value; + } +} diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.h b/features/lorawan/lorastack/phy/LoRaPHYUS915.h index 2c883ae69d..577611ba9c 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.h +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.h @@ -80,6 +80,26 @@ public: private: + /** + * Sets the intersection of source and destination channel masks + * into the destination. + */ + void intersect_channel_mask(const uint16_t *source, uint16_t *destination, + uint8_t size); + + /** + * Fills channel mask array based upon the provided FSB mask + */ + void fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *channel_mask, uint8_t size); + + /** + * Fills channel mask array with a given value + */ + void fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size); + int8_t limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, int8_t datarate);