diff --git a/LICENSE.md b/LICENSE.md index 6a5d58c..26f2e47 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -12,7 +12,7 @@ - [features/FEATURE_PSA/FEATURE_TFM](./features/FEATURE_PSA/FEATURE_TFM) - BSD-3-Clause - [features/FEATURE_PSA/FEATURE_MBED_PSA_SRV/services/attestation](./features/FEATURE_PSA/TARGET_MBED_PSA_SRV/services/attestation) - BSD-3-Clause - [features/FEATURE_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor](./features/FEATURE_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor) - BSD-3-Clause -- [features/lorawan](./features/lorawan) - Revised BSD +- [connectivity/lorawan](./features/lorawan) - Revised BSD - [connectivity/lwipstack](./connectivity/lwipstack) - BSD-style, MIT-style - [connectivity/nanostack/sal-stack-nanostack](./connectivity/nanostack/sal-stack-nanostack) - BSD-3-Clause - [features/frameworks/unity/unity](./features/frameworks/unity/unity) - MIT diff --git a/TESTS/lorawan/loraradio/README.md b/TESTS/lorawan/loraradio/README.md deleted file mode 100644 index 562a24e..0000000 --- a/TESTS/lorawan/loraradio/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Description - -This document describes how to run LoRaRadio API tests. - -## Configuring target HW - -Before starting to test, the target HW must be configured for the test. This can be done by either modifying the application configuration `json` file (if using currently supported Semtech SX1272 or SX1276 radios) or implementing driver construction into test source. - -The default mbed_app.json file provides configuration for some already supported HWs. - -## Running tests - -You can use the following command to run tests: - -`mbed test -n mbed-os-tests-lorawan-loraradio -m TARGET -t GCC_ARM --app-config mbed-os/TESTS/lorawan/loraradio/template_mbed_app.txt` - -Replace TARGET with the target device. diff --git a/TESTS/lorawan/loraradio/main.cpp b/TESTS/lorawan/loraradio/main.cpp deleted file mode 100644 index fa9706e..0000000 --- a/TESTS/lorawan/loraradio/main.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] LORADIO test cases require a RTOS to run. -#else - -#include "utest.h" -#include "unity.h" -#include "greentea-client/test_env.h" - -#include "Semaphore.h" - -#include "mbed_trace.h" -#define TRACE_GROUP "RTST" - -#include "LoRaRadio.h" - -#define SX1272 0xFF -#define SX1276 0xEE - -#if (MBED_CONF_APP_LORA_RADIO == SX1272) -#include "SX1272_LoRaRadio.h" -#elif (MBED_CONF_APP_LORA_RADIO == SX1276) -#include "SX1276_LoRaRadio.h" -#else -#error [NOT_SUPPORTED] Requires parameters from application config file. -#endif - -#if (MBED_CONF_APP_LORA_RADIO == SX1272) || (MBED_CONF_APP_LORA_RADIO == SX1276) - -using namespace utest::v1; -using namespace mbed; - -static LoRaRadio *radio = NULL; -rtos::Semaphore event_sem(0); - -enum event_t { - EV_NONE, - EV_TX_DONE, - EV_TX_TIMEOUT, - EV_RX_DONE, - EV_RX_TIMEOUT, - EV_RX_ERROR, -}; -static volatile event_t received_event; - - -static void tx_done() -{ - ThisThread::sleep_for(2); - TEST_ASSERT_EQUAL(EV_NONE, received_event); - received_event = EV_TX_DONE; - TEST_ASSERT_EQUAL(osOK, event_sem.release()); -} - -static void tx_timeout() -{ - ThisThread::sleep_for(2); - TEST_ASSERT_EQUAL(EV_NONE, received_event); - received_event = EV_TX_TIMEOUT; - TEST_ASSERT_EQUAL(osOK, event_sem.release()); -} - -static void rx_done(const uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) -{ - ThisThread::sleep_for(2); - TEST_ASSERT_EQUAL(EV_NONE, received_event); - received_event = EV_RX_DONE; - TEST_ASSERT_EQUAL(osOK, event_sem.release()); -} - -static void rx_timeout() -{ - ThisThread::sleep_for(2); - TEST_ASSERT_EQUAL(EV_NONE, received_event); - received_event = EV_RX_TIMEOUT; - TEST_ASSERT_EQUAL(osOK, event_sem.release()); -} - -static void rx_error() -{ - ThisThread::sleep_for(2); - TEST_ASSERT_EQUAL(EV_NONE, received_event); - received_event = EV_RX_ERROR; - TEST_ASSERT_EQUAL(osOK, event_sem.release()); -} - -static radio_events radio_callbacks = { - .tx_done = tx_done, - .tx_timeout = tx_timeout, - .rx_done = rx_done, - .rx_timeout = rx_timeout, - .rx_error = rx_error -}; - - -void test_random() -{ - const uint32_t rand1 = radio->random(); - const uint32_t rand2 = radio->random(); - TEST_ASSERT_NOT_EQUAL(rand1, rand2); -} - -void test_set_tx_config() -{ - uint8_t buffer[] = {0}; - - TEST_ASSERT_EQUAL(RF_IDLE, radio->get_status()); - - radio->set_tx_config(MODEM_LORA, 13, 0, - 0, 7, - 1, 8, - false, true, false, - 0, false, 100); - radio->send(buffer, sizeof(buffer)); - - TEST_ASSERT_EQUAL(RF_TX_RUNNING, radio->get_status()); - - TEST_ASSERT_TRUE(event_sem.try_acquire_for(1000)); - TEST_ASSERT_EQUAL(EV_TX_DONE, received_event); - received_event = EV_NONE; -} - -void test_set_rx_config() -{ - TEST_ASSERT_EQUAL(RF_IDLE, radio->get_status()); - - radio->set_rx_config(MODEM_LORA, 0, // modem, bandwidth, - 7, 1, // datarate, coderate, - 0, 8, // bandwidth_afc, preamble_len, - 24, false, // symb_timeout, fix_len, - 0, // payload_len, - false, false, 0, // crc_on, freq_hop_on, hop_period, - true, false); // iq_inverted, rx_continuous - radio->receive(100); - - TEST_ASSERT_EQUAL(RF_RX_RUNNING, radio->get_status()); - - TEST_ASSERT_TRUE(event_sem.try_acquire_for(1000)); - - // Nobody was sending to us so timeout is expected. - TEST_ASSERT_EQUAL(EV_RX_TIMEOUT, received_event); - received_event = EV_NONE; -} - -void test_time_on_air() -{ - radio->set_rx_config(MODEM_LORA, 0, - 7, 1, - 0, 8, - 24, false, - 0, - false, false, 0, - true, false); - TEST_ASSERT_EQUAL(52, radio->time_on_air(MODEM_LORA, 20)); - - radio->set_tx_config(MODEM_LORA, 13, 0, - 0, 7, - 1, 8, - false, true, false, - 0, false, 100); - TEST_ASSERT_EQUAL(72, radio->time_on_air(MODEM_LORA, 32)); - - // TODO: Add FSK tests -} - -void test_perform_carrier_sense() -{ - TEST_ASSERT_TRUE(radio->perform_carrier_sense(MODEM_FSK, 865000000, -20, 1)); - TEST_ASSERT_TRUE(radio->perform_carrier_sense(MODEM_LORA, 865000000, -20, 1)); -} - -void test_check_rf_frequency() -{ - // Test EU868 frequency - TEST_ASSERT_TRUE(radio->check_rf_frequency(865000000)); -} - -// Test setup -utest::v1::status_t test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(20, "default_auto"); - - mbed_trace_init(); - - return verbose_test_setup_handler(number_of_cases); -} - -utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) -{ -#if (MBED_CONF_APP_LORA_RADIO == SX1272) - - radio = new SX1272_LoRaRadio(MBED_CONF_APP_LORA_SPI_MOSI, - MBED_CONF_APP_LORA_SPI_MISO, - MBED_CONF_APP_LORA_SPI_SCLK, - MBED_CONF_APP_LORA_CS, - MBED_CONF_APP_LORA_RESET, - MBED_CONF_APP_LORA_DIO0, - MBED_CONF_APP_LORA_DIO1, - MBED_CONF_APP_LORA_DIO2, - MBED_CONF_APP_LORA_DIO3, - MBED_CONF_APP_LORA_DIO4, - MBED_CONF_APP_LORA_DIO5, - MBED_CONF_APP_LORA_RF_SWITCH_CTL1, - MBED_CONF_APP_LORA_RF_SWITCH_CTL2, - MBED_CONF_APP_LORA_TXCTL, - MBED_CONF_APP_LORA_RXCTL, - MBED_CONF_APP_LORA_ANT_SWITCH, - MBED_CONF_APP_LORA_PWR_AMP_CTL, - MBED_CONF_APP_LORA_TCXO); - -#elif (MBED_CONF_APP_LORA_RADIO == SX1276) - - radio = new SX1276_LoRaRadio(MBED_CONF_APP_LORA_SPI_MOSI, - MBED_CONF_APP_LORA_SPI_MISO, - MBED_CONF_APP_LORA_SPI_SCLK, - MBED_CONF_APP_LORA_CS, - MBED_CONF_APP_LORA_RESET, - MBED_CONF_APP_LORA_DIO0, - MBED_CONF_APP_LORA_DIO1, - MBED_CONF_APP_LORA_DIO2, - MBED_CONF_APP_LORA_DIO3, - MBED_CONF_APP_LORA_DIO4, - MBED_CONF_APP_LORA_DIO5, - MBED_CONF_APP_LORA_RF_SWITCH_CTL1, - MBED_CONF_APP_LORA_RF_SWITCH_CTL2, - MBED_CONF_APP_LORA_TXCTL, - MBED_CONF_APP_LORA_RXCTL, - MBED_CONF_APP_LORA_ANT_SWITCH, - MBED_CONF_APP_LORA_PWR_AMP_CTL, - MBED_CONF_APP_LORA_TCXO); - -#else -#error [NOT_SUPPORTED] Unknown LoRa radio specified (SX1272,SX1276 are valid) -#endif - - TEST_ASSERT(radio); - radio->init_radio(&radio_callbacks); - radio->sleep(); - - return greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) -{ - radio->sleep(); - -#if (MBED_CONF_APP_LORA_RADIO == SX1272) - delete static_cast(radio); -#elif (MBED_CONF_APP_LORA_RADIO == SX1276) - delete static_cast(radio); -#else -#error [NOT_SUPPORTED] Unknown LoRa radio specified (SX1272,SX1276 are valid) -#endif - radio = NULL; - - return greentea_case_teardown_handler(source, passed, failed, reason); -} - -const Case cases[] = { - Case("Test random", case_setup_handler, test_random, case_teardown_handler), - Case("Test set_tx_config", case_setup_handler, test_set_tx_config, case_teardown_handler), - Case("Test set_rx_config", case_setup_handler, test_set_rx_config, case_teardown_handler), - Case("Test time_on_air", case_setup_handler, test_time_on_air, case_teardown_handler), - Case("Test perform_carrier_sense", case_setup_handler, test_perform_carrier_sense, case_teardown_handler), - Case("Test check_rf_frequency", case_setup_handler, test_check_rf_frequency, case_teardown_handler), -}; - -Specification specification(test_setup, cases); - -int main() -{ - return !Harness::run(specification); -} - -#endif // (MBED_CONF_APP_LORA_RADIO == SX1272) || (MBED_CONF_APP_LORA_RADIO == SX1276) -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/TESTS/lorawan/loraradio/template_mbed_app.txt b/TESTS/lorawan/loraradio/template_mbed_app.txt deleted file mode 100644 index a4d6fd5..0000000 --- a/TESTS/lorawan/loraradio/template_mbed_app.txt +++ /dev/null @@ -1,160 +0,0 @@ -{ - "config": { - "lora-radio": { - "help": "Which radio to use (options: SX1272,SX1276)", - "value": "SX1276" - }, - - "lora-spi-mosi": { "value": "NC" }, - "lora-spi-miso": { "value": "NC" }, - "lora-spi-sclk": { "value": "NC" }, - "lora-cs": { "value": "NC" }, - "lora-reset": { "value": "NC" }, - "lora-dio0": { "value": "NC" }, - "lora-dio1": { "value": "NC" }, - "lora-dio2": { "value": "NC" }, - "lora-dio3": { "value": "NC" }, - "lora-dio4": { "value": "NC" }, - "lora-dio5": { "value": "NC" }, - "lora-rf-switch-ctl1": { "value": "NC" }, - "lora-rf-switch-ctl2": { "value": "NC" }, - "lora-txctl": { "value": "NC" }, - "lora-rxctl": { "value": "NC" }, - "lora-ant-switch": { "value": "NC" }, - "lora-pwr-amp-ctl": { "value": "NC" }, - "lora-tcxo": { "value": "NC" } - }, - "target_overrides": { - - "K64F": { - "lora-spi-mosi": "D11", - "lora-spi-miso": "D12", - "lora-spi-sclk": "D13", - "lora-cs": "D10", - "lora-reset": "A0", - "lora-dio0": "D2", - "lora-dio1": "D3", - "lora-dio2": "D4", - "lora-dio3": "D5", - "lora-dio4": "D8", - "lora-dio5": "D9", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "NC", - "lora-rxctl": "NC", - "lora-ant-switch": "A4", - "lora-pwr-amp-ctl": "NC", - "lora-tcxo": "NC" - }, - - "DISCO_L072CZ_LRWAN1": { - "lora-radio": "SX1276", - "lora-spi-mosi": "PA_7", - "lora-spi-miso": "PA_6", - "lora-spi-sclk": "PB_3", - "lora-cs": "PA_15", - "lora-reset": "PC_0", - "lora-dio0": "PB_4", - "lora-dio1": "PB_1", - "lora-dio2": "PB_0", - "lora-dio3": "PC_13", - "lora-dio4": "NC", - "lora-dio5": "NC", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "PC_2", - "lora-rxctl": "PA_1", - "lora-ant-switch": "NC", - "lora-pwr-amp-ctl": "PC_1", - "lora-tcxo": "PA_12" - }, - - "XDOT_L151CC": { - "lora-radio": "SX1272", - "lora-spi-mosi": "LORA_MOSI", - "lora-spi-miso": "LORA_MISO", - "lora-spi-sclk": "LORA_SCK", - "lora-cs": "LORA_NSS", - "lora-reset": "LORA_RESET", - "lora-dio0": "LORA_DIO0", - "lora-dio1": "LORA_DIO1", - "lora-dio2": "LORA_DIO2", - "lora-dio3": "LORA_DIO3", - "lora-dio4": "LORA_DIO4", - "lora-dio5": "NC", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "NC", - "lora-rxctl": "NC", - "lora-ant-switch": "NC", - "lora-pwr-amp-ctl": "NC", - "lora-tcxo": "NC" - }, - - "LTEK_FF1705": { - "lora-radio": "SX1272", - "lora-spi-mosi": "LORA_MOSI", - "lora-spi-miso": "LORA_MISO", - "lora-spi-sclk": "LORA_SCK", - "lora-cs": "LORA_NSS", - "lora-reset": "LORA_RESET", - "lora-dio0": "LORA_DIO0", - "lora-dio1": "LORA_DIO1", - "lora-dio2": "LORA_DIO2", - "lora-dio3": "LORA_DIO3", - "lora-dio4": "LORA_DIO4", - "lora-dio5": "NC", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "NC", - "lora-rxctl": "NC", - "lora-ant-switch": "NC", - "lora-pwr-amp-ctl": "NC", - "lora-tcxo": "NC" - }, - - "MTS_MDOT_F411RE": { - "lora-radio": "SX1272", - "lora-spi-mosi": "LORA_MOSI", - "lora-spi-miso": "LORA_MISO", - "lora-spi-sclk": "LORA_SCK", - "lora-cs": "LORA_NSS", - "lora-reset": "LORA_RESET", - "lora-dio0": "LORA_DIO0", - "lora-dio1": "LORA_DIO1", - "lora-dio2": "LORA_DIO2", - "lora-dio3": "LORA_DIO3", - "lora-dio4": "LORA_DIO4", - "lora-dio5": "LORA_DIO5", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "LORA_TXCTL", - "lora-rxctl": "LORA_RXCTL", - "lora-ant-switch": "NC", - "lora-pwr-amp-ctl": "NC", - "lora-tcxo": "NC" - }, - - "ADV_WISE_1510": { - "lora-radio": "SX1276", - "lora-spi-mosi": "SPI_RF_MOSI", - "lora-spi-miso": "SPI_RF_MISO", - "lora-spi-sclk": "SPI_RF_SCK", - "lora-cs": "SPI_RF_CS", - "lora-reset": "SPI_RF_RESET", - "lora-dio0": "DIO0", - "lora-dio1": "DIO1", - "lora-dio2": "DIO2", - "lora-dio3": "DIO3", - "lora-dio4": "DIO4", - "lora-dio5": "DIO5", - "lora-rf-switch-ctl1": "NC", - "lora-rf-switch-ctl2": "NC", - "lora-txctl": "NC", - "lora-rxctl": "NC", - "lora-ant-switch": "ANT_SWITCH", - "lora-pwr-amp-ctl": "NC", - "lora-tcxo": "NC" - } - } -} diff --git a/UNITTESTS/CMakeLists.txt b/UNITTESTS/CMakeLists.txt index 77e7f8f..e54d21a 100644 --- a/UNITTESTS/CMakeLists.txt +++ b/UNITTESTS/CMakeLists.txt @@ -146,11 +146,11 @@ "${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/device" "${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework" "${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/common" - "${PROJECT_SOURCE_DIR}/../features/lorawan" - "${PROJECT_SOURCE_DIR}/../features/lorawan/lorastack" - "${PROJECT_SOURCE_DIR}/../features/lorawan/lorastack/mac" - "${PROJECT_SOURCE_DIR}/../features/lorawan/lorastack/phy" - "${PROJECT_SOURCE_DIR}/../features/lorawan/system" + "${PROJECT_SOURCE_DIR}/../connectivity/lorawan" + "${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack" + "${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack/mac" + "${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack/phy" + "${PROJECT_SOURCE_DIR}/../connectivity/lorawan/system" "${PROJECT_SOURCE_DIR}/../connectivity/mbedtls" "${PROJECT_SOURCE_DIR}/../connectivity/mbedtls/include" ) diff --git a/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp b/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp deleted file mode 100644 index 8edee42..0000000 --- a/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaMac.h" -#include "LoRaPHY_stub.h" -#include "LoRaMacCrypto_stub.h" -#include "LoRaMacCommand_stub.h" -#include "LoRaWANTimer_stub.h" -#include "EventQueue_stub.h" - -using namespace events; - -class my_phy : public LoRaPHY { -public: - my_phy() - { - }; - - virtual ~my_phy() - { - }; -}; - -class Test_LoRaMac : public testing::Test { -protected: - LoRaMac *object; - - virtual void SetUp() - { - object = new LoRaMac(); - LoRaWANTimer_stub::time_value = 1; - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaMac, constructor) -{ - EXPECT_TRUE(object); -} - -void my_cb() -{ - -} - -TEST_F(Test_LoRaMac, initialize) -{ - my_phy phy; - object->bind_phy(phy); - - lorawan_connect_t conn; - memset(&conn, 0, sizeof(conn)); - uint8_t key[16]; - memset(key, 0, sizeof(key)); - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 2; - object->prepare_join(&conn, true); - - channel_params_t params[] = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; - LoRaPHY_stub::channel_params_ptr = params; - - LoRaWANTimer_stub::call_cb_immediately = true; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb)); -} - -TEST_F(Test_LoRaMac, disconnect) -{ - object->disconnect(); -} - -TEST_F(Test_LoRaMac, nwk_joined) -{ - EXPECT_EQ(false, object->nwk_joined()); -} - -TEST_F(Test_LoRaMac, add_channel_plan) -{ - lorawan_channelplan_t plan; - EXPECT_EQ(LORAWAN_STATUS_OK, object->add_channel_plan(plan)); - - object->set_tx_ongoing(true); - EXPECT_EQ(LORAWAN_STATUS_BUSY, object->add_channel_plan(plan)); -} - -TEST_F(Test_LoRaMac, remove_channel_plan) -{ - EXPECT_EQ(LORAWAN_STATUS_OK, object->remove_channel_plan()); - - object->set_tx_ongoing(true); - EXPECT_EQ(LORAWAN_STATUS_BUSY, object->remove_channel_plan()); -} - -TEST_F(Test_LoRaMac, get_channel_plan) -{ - lorawan_channelplan_t plan; - EXPECT_EQ(LORAWAN_STATUS_OK, object->get_channel_plan(plan)); -} - -TEST_F(Test_LoRaMac, remove_single_channel) -{ - EXPECT_EQ(LORAWAN_STATUS_OK, object->remove_single_channel(1)); - - object->set_tx_ongoing(true); - EXPECT_EQ(LORAWAN_STATUS_BUSY, object->remove_single_channel(1)); -} - -TEST_F(Test_LoRaMac, multicast_channel_link) -{ - multicast_params_t p; - memset(&p, 0, sizeof(p)); - - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->multicast_channel_link(NULL)); - - object->set_tx_ongoing(true); - EXPECT_EQ(LORAWAN_STATUS_BUSY, object->multicast_channel_link(&p)); - - object->set_tx_ongoing(false); - EXPECT_EQ(LORAWAN_STATUS_OK, object->multicast_channel_link(&p)); -} - -TEST_F(Test_LoRaMac, multicast_channel_unlink) -{ - multicast_params_t p; - memset(&p, 0, sizeof(p)); - - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->multicast_channel_unlink(NULL)); - - object->set_tx_ongoing(true); - EXPECT_EQ(LORAWAN_STATUS_BUSY, object->multicast_channel_unlink(&p)); - - object->set_tx_ongoing(false); - EXPECT_EQ(LORAWAN_STATUS_OK, object->multicast_channel_unlink(&p)); -} - -TEST_F(Test_LoRaMac, send) -{ - loramac_mhdr_t mac_hdr; - memset(&mac_hdr, 0, sizeof(mac_hdr)); - uint8_t buf[15]; - memset(buf, 0, sizeof(buf)); - mac_hdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; - object->send(&mac_hdr, 1, buf, 15); -} - -TEST_F(Test_LoRaMac, get_default_tx_datarate) -{ - object->get_default_tx_datarate(); -} - -TEST_F(Test_LoRaMac, enable_adaptive_datarate) -{ - object->enable_adaptive_datarate(true); -} - -TEST_F(Test_LoRaMac, set_channel_data_rate) -{ - object->set_channel_data_rate(8); -} - -TEST_F(Test_LoRaMac, tx_ongoing) -{ - object->tx_ongoing(); -} - -TEST_F(Test_LoRaMac, set_tx_ongoing) -{ - object->set_tx_ongoing(true); -} - -TEST_F(Test_LoRaMac, reset_ongoing_tx) -{ - object->reset_ongoing_tx(true); -} - -TEST_F(Test_LoRaMac, prepare_ongoing_tx) -{ - uint8_t buf[16]; - memset(buf, 0, sizeof(buf)); - object->prepare_ongoing_tx(1, buf, 16, 1, 0); -} - -TEST_F(Test_LoRaMac, send_ongoing_tx) -{ - object->send_ongoing_tx(); -} - -TEST_F(Test_LoRaMac, get_device_class) -{ - object->get_device_class(); -} - -void exp_cb() -{ - -} - -TEST_F(Test_LoRaMac, set_device_class) -{ - object->set_device_class(CLASS_B, exp_cb); - - my_phy phy; - object->bind_phy(phy); - object->set_device_class(CLASS_C, exp_cb); -} - -TEST_F(Test_LoRaMac, setup_link_check_request) -{ - object->setup_link_check_request(); -} - -TEST_F(Test_LoRaMac, prepare_join) -{ - lorawan_connect_t conn; - memset(&conn, 0, sizeof(conn)); - object->prepare_join(&conn, false); - - my_phy phy; - object->bind_phy(phy); - EXPECT_EQ(LORAWAN_STATUS_OK, object->join(false)); - - uint8_t key[16]; - conn.connection_u.otaa.app_key = NULL; - conn.connection_u.otaa.app_eui = NULL; - conn.connection_u.otaa.dev_eui = NULL; - conn.connection_u.otaa.nb_trials = 0; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); - - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = NULL; - conn.connection_u.otaa.dev_eui = NULL; - conn.connection_u.otaa.nb_trials = 0; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); - - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = NULL; - conn.connection_u.otaa.nb_trials = 0; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); - - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 0; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); - - LoRaPHY_stub::bool_table[0] = false; - LoRaPHY_stub::bool_counter = 0; - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 2; - EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(&conn, true)); - - conn.connection_u.abp.dev_addr = 0; - conn.connection_u.abp.nwk_id = 0; - conn.connection_u.abp.nwk_skey = NULL; - conn.connection_u.abp.app_skey = NULL; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); - - conn.connection_u.abp.dev_addr = 1; - conn.connection_u.abp.nwk_id = 0; - conn.connection_u.abp.nwk_skey = NULL; - conn.connection_u.abp.app_skey = NULL; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); - - conn.connection_u.abp.dev_addr = 1; - conn.connection_u.abp.nwk_id = 2; - conn.connection_u.abp.nwk_skey = NULL; - conn.connection_u.abp.app_skey = NULL; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); - - conn.connection_u.abp.dev_addr = 1; - conn.connection_u.abp.nwk_id = 2; - conn.connection_u.abp.nwk_skey = key; - conn.connection_u.abp.app_skey = NULL; - EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); - - conn.connection_u.abp.dev_addr = 1; - conn.connection_u.abp.nwk_id = 2; - conn.connection_u.abp.nwk_skey = key; - conn.connection_u.abp.app_skey = key; - EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(&conn, false)); - - EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(NULL, false)); -} - -TEST_F(Test_LoRaMac, join) -{ - my_phy phy; - object->bind_phy(phy); - EXPECT_EQ(LORAWAN_STATUS_OK, object->join(false)); - - lorawan_connect_t conn; - memset(&conn, 0, sizeof(conn)); - uint8_t key[16]; - memset(key, 0, sizeof(key)); - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 2; - object->prepare_join(&conn, true); - EXPECT_EQ(LORAWAN_STATUS_CONNECT_IN_PROGRESS, object->join(true)); -} - -TEST_F(Test_LoRaMac, on_radio_tx_done) -{ - my_phy phy; - object->bind_phy(phy); - object->on_radio_tx_done(100); -} - -TEST_F(Test_LoRaMac, on_radio_rx_done) -{ - uint8_t buf[16]; - memset(buf, 0, sizeof(buf)); - object->on_radio_rx_done(buf, 16, 0, 0); -} - -TEST_F(Test_LoRaMac, on_radio_tx_timeout) -{ - object->on_radio_tx_timeout(); -} - -TEST_F(Test_LoRaMac, on_radio_rx_timeout) -{ - object->on_radio_rx_timeout(true); -} - -TEST_F(Test_LoRaMac, continue_joining_process) -{ - my_phy phy; - object->bind_phy(phy); - lorawan_connect_t conn; - memset(&conn, 0, sizeof(conn)); - uint8_t key[16]; - memset(key, 0, sizeof(key)); - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 2; - object->prepare_join(&conn, true); - object->continue_joining_process(); -} - -TEST_F(Test_LoRaMac, continue_sending_process) -{ - my_phy phy; - object->bind_phy(phy); - object->continue_sending_process(); -} - -TEST_F(Test_LoRaMac, get_mcps_confirmation) -{ - object->get_mcps_confirmation(); -} - -TEST_F(Test_LoRaMac, get_mcps_indication) -{ - object->get_mcps_indication(); -} - -TEST_F(Test_LoRaMac, get_mlme_confirmation) -{ - object->get_mlme_confirmation(); -} - -TEST_F(Test_LoRaMac, get_mlme_indication) -{ - object->get_mlme_indication(); -} - -TEST_F(Test_LoRaMac, post_process_mcps_req) -{ - uint8_t data[16]; - memset(data, 0, sizeof(data)); - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - - my_phy phy; - object->bind_phy(phy); - object->join(false); - - object->prepare_ongoing_tx(1, data, 15, 0x01, 2); - object->send_ongoing_tx(); - object->post_process_mcps_req(); - - LoRaPHY_stub::bool_counter = 0; - object->prepare_ongoing_tx(1, data, 15, 0x02, 2); - object->send_ongoing_tx(); - object->post_process_mcps_req(); - - //_mcps_confirmation.ack_received missing here - uint8_t payload[16] = {}; - LoRaPHY_stub::uint16_value = 5; - payload[0] = FRAME_TYPE_DATA_CONFIRMED_DOWN << 5; - payload[5] = 1 << 5; - - //address != _params.dev_addr - payload[2] = 2; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - payload[2] = 0; - //mic failure - payload[13] = 2; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - payload[13] = 0; - //crypto failure - LoRaMacCrypto_stub::int_table_idx_value = 0; - LoRaMacCrypto_stub::int_table[0] = 4; - LoRaMacCrypto_stub::int_table[1] = 4; -// LoRaPHY_stub::uint16_value = 0; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - //process_mac_commands failure - LoRaMacCommand_stub::status_value = LORAWAN_STATUS_BUSY; - LoRaMacCrypto_stub::int_table[0] = 0; - LoRaMacCrypto_stub::int_table[1] = 0; - payload[7] = 1; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - //FOpts_len != 0 - payload[5] = (1 << 5) + 1; - payload[7] = 0; - LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; - payload[0] = FRAME_TYPE_DATA_UNCONFIRMED_DOWN << 5; - - object->on_radio_rx_done(payload, 13, 0, 0); - - //_mac_commands.process_mac_commands fails - LoRaMacCommand_stub::status_value = LORAWAN_STATUS_DATARATE_INVALID; - object->on_radio_rx_done(payload, 13, 0, 0); - - object->post_process_mcps_req(); - - payload[9] = 1; - LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; - payload[0] = FRAME_TYPE_PROPRIETARY << 5; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - payload[9] = 0; - payload[5] = 1 << 5; - LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; - object->on_radio_rx_done(payload, 16, 0, 0); - object->post_process_mcps_req(); - - LoRaPHY_stub::bool_counter = 0; - object->prepare_ongoing_tx(1, data, 15, 0x04, 2); - object->send_ongoing_tx(); - object->post_process_mcps_req(); - - LoRaPHY_stub::bool_counter = 0; - object->prepare_ongoing_tx(1, data, 15, 0x08, 2); - object->send_ongoing_tx(); - object->post_process_mcps_req(); -} - -TEST_F(Test_LoRaMac, handle_join_accept_frame) -{ - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - - my_phy phy; - object->bind_phy(phy); - - uint8_t payload[16] = {}; - LoRaPHY_stub::uint16_value = 5; - payload[0] = FRAME_TYPE_JOIN_ACCEPT << 5; - payload[5] = 1 << 5; - - LoRaMacCrypto_stub::int_table_idx_value = 0; - LoRaMacCrypto_stub::int_table[0] = 4; - LoRaMacCrypto_stub::int_table[1] = 4; - LoRaMacCrypto_stub::int_table[2] = 4; - LoRaMacCrypto_stub::int_table[3] = 4; - object->on_radio_rx_done(payload, 16, 0, 0); - - LoRaMacCrypto_stub::int_table_idx_value = 0; - LoRaMacCrypto_stub::int_table[0] = 0; - object->on_radio_rx_done(payload, 16, 0, 0); - - LoRaMacCrypto_stub::int_table_idx_value = 0; - LoRaMacCrypto_stub::int_table[1] = 0; - object->on_radio_rx_done(payload, 16, 0, 0); - - //mic failure case - payload[13] = 17; - LoRaMacCrypto_stub::int_table_idx_value = 0; - object->on_radio_rx_done(payload, 16, 0, 0); - - payload[13] = 0; - LoRaMacCrypto_stub::int_table_idx_value = 0; - LoRaMacCrypto_stub::int_table[2] = 0; - object->on_radio_rx_done(payload, 16, 0, 0); -} - -TEST_F(Test_LoRaMac, post_process_mcps_ind) -{ - object->post_process_mcps_ind(); -} - -TEST_F(Test_LoRaMac, post_process_mlme_request) -{ - object->post_process_mlme_request(); -} - -TEST_F(Test_LoRaMac, post_process_mlme_ind) -{ - object->post_process_mlme_ind(); -} - -uint8_t batt_cb() -{ - -} - -TEST_F(Test_LoRaMac, set_batterylevel_callback) -{ - object->set_batterylevel_callback(batt_cb); -} - -TEST_F(Test_LoRaMac, get_backoff_timer_event_id) -{ - object->get_backoff_timer_event_id(); -} - -TEST_F(Test_LoRaMac, clear_tx_pipe) -{ - EXPECT_EQ(LORAWAN_STATUS_NO_OP, object->clear_tx_pipe()); //timer id == 0 - - my_phy phy; - object->bind_phy(phy); - - lorawan_connect_t conn; - memset(&conn, 0, sizeof(conn)); - uint8_t key[16]; - memset(key, 0, sizeof(key)); - conn.connection_u.otaa.app_key = key; - conn.connection_u.otaa.app_eui = key; - conn.connection_u.otaa.dev_eui = key; - conn.connection_u.otaa.nb_trials = 2; - object->prepare_join(&conn, true); - - channel_params_t params[] = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; - LoRaPHY_stub::channel_params_ptr = params; - LoRaWANTimer_stub::call_cb_immediately = true; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb)); - EventQueue_stub::int_value = 0; - 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; - EXPECT_EQ(LORAWAN_STATUS_OK, object->clear_tx_pipe()); -} - -TEST_F(Test_LoRaMac, get_current_time) -{ - object->get_current_time(); -} - -TEST_F(Test_LoRaMac, get_current_slot) -{ - object->get_current_slot(); -} - -TEST_F(Test_LoRaMac, get_QOS_level) -{ - EXPECT_EQ(0, object->get_QOS_level()); -} - -TEST_F(Test_LoRaMac, get_prev_QOS_level) -{ - EXPECT_EQ(1, object->get_prev_QOS_level()); -} diff --git a/UNITTESTS/features/lorawan/loramac/unittest.cmake b/UNITTESTS/features/lorawan/loramac/unittest.cmake deleted file mode 100644 index f68bee2..0000000 --- a/UNITTESTS/features/lorawan/loramac/unittest.cmake +++ /dev/null @@ -1,63 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaMac") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/mac/LoRaMac.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/mac -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loramac/Test_LoRaMac.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANStack_stub.cpp - stubs/mbed_assert_stub.cpp - stubs/LoRaMacCrypto_stub.cpp - stubs/LoRaMacChannelPlan_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/LoRaMacCommand_stub.cpp - stubs/EventQueue_stub.cpp - stubs/Mutex_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_ADR_ON=true - -DMBED_CONF_LORA_PUBLIC_NETWORK=true - -DMBED_CONF_LORA_NB_TRIALS=2 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_DUTY_CYCLE_ON=true - -DMBED_CONF_LORA_MAX_SYS_RX_ERROR=10 - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DEVICE_ADDRESS=0x00000000 -) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_NWKSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_NWKSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_APPSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_APPSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") - - diff --git a/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp b/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp deleted file mode 100644 index 7150ec1..0000000 --- a/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaMacChannelPlan.h" -#include "LoRaPHY_stub.h" -#include "LoRaPHY.h" - -class my_LoRaPHY : public LoRaPHY { -public: - my_LoRaPHY() - { - }; - - virtual ~my_LoRaPHY() - { - }; -}; - - -class Test_LoRaMacChannelPlan : public testing::Test { -protected: - LoRaMacChannelPlan *object; - my_LoRaPHY phy; - - virtual void SetUp() - { - object = new LoRaMacChannelPlan(); - object->activate_channelplan_subsystem(&phy); - - LoRaPHY_stub::uint8_value = 0; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_OK; - LoRaPHY_stub::uint16_value = 0; - memcpy(LoRaPHY_stub::bool_table, "0", 20); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaMacChannelPlan, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaMacChannelPlan, set_plan) -{ - lorawan_channelplan_t plan; - memset(&plan, 0, sizeof(plan)); - memset(&LoRaPHY_stub::bool_table, 0, sizeof(LoRaPHY_stub::bool_table)); - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = false; - EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_SERVICE_UNKNOWN); - - plan.nb_channels = 1; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_PARAMETER_INVALID); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::uint8_value = 10; - LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_PARAMETER_INVALID; - loramac_channel_t chan; - memset(&chan, 0, sizeof(chan)); - plan.channels = &chan; - EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_PARAMETER_INVALID); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - plan.nb_channels = 2; - LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_OK); -} - -TEST_F(Test_LoRaMacChannelPlan, get_plan) -{ - lorawan_channelplan_t plan; - channel_params_t params; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = false; - EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_SERVICE_UNKNOWN); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = false; - - LoRaPHY_stub::uint8_value = 1; - LoRaPHY_stub::uint16_value = 0xABCD; - EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_OK); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = true; - LoRaPHY_stub::bool_table[2] = false; - loramac_channel_t ch; - plan.channels = &ch; - EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_OK); -} - -TEST_F(Test_LoRaMacChannelPlan, remove_plan) -{ - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = false; - EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_SERVICE_UNKNOWN); - - LoRaPHY_stub::uint8_value = 4; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = true; //first continue - LoRaPHY_stub::bool_table[2] = false; - LoRaPHY_stub::bool_table[3] = false;//second continue - LoRaPHY_stub::bool_table[4] = false; - LoRaPHY_stub::bool_table[5] = true; - LoRaPHY_stub::bool_table[6] = false;//false for remove_single_channel(i) - - EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_SERVICE_UNKNOWN); - - LoRaPHY_stub::uint8_value = 3; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = false; - LoRaPHY_stub::bool_table[2] = true; - LoRaPHY_stub::bool_table[3] = true; - LoRaPHY_stub::bool_table[4] = true; - LoRaPHY_stub::bool_table[5] = true; - LoRaPHY_stub::bool_table[7] = true; - LoRaPHY_stub::bool_table[8] = true; - LoRaPHY_stub::bool_table[9] = true; - LoRaPHY_stub::bool_table[10] = true; - - EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_OK); - -} - -TEST_F(Test_LoRaMacChannelPlan, remove_single_channel) -{ - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = false; - EXPECT_TRUE(object->remove_single_channel(4) == LORAWAN_STATUS_SERVICE_UNKNOWN); - - LoRaPHY_stub::uint8_value = 2; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - - EXPECT_TRUE(object->remove_single_channel(4) == LORAWAN_STATUS_PARAMETER_INVALID); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = false; - EXPECT_TRUE(object->remove_single_channel(1) == LORAWAN_STATUS_PARAMETER_INVALID); - - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = true; - EXPECT_TRUE(object->remove_single_channel(1) == LORAWAN_STATUS_OK); -} - diff --git a/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake b/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake deleted file mode 100644 index 4bc3c0a..0000000 --- a/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaMacChannelPlan") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/mac -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp - stubs/LoRaPHY_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 -) diff --git a/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp b/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp deleted file mode 100644 index b9430ea..0000000 --- a/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaMacCommand.h" - -#include "LoRaPHY_stub.h" - -class my_LoRaPHY : public LoRaPHY { -public: - my_LoRaPHY() - { - }; - - virtual ~my_LoRaPHY() - { - }; -}; - -uint8_t my_cb() -{ - return 1; -} - -class Test_LoRaMacCommand : public testing::Test { -protected: - LoRaMacCommand *object; - - virtual void SetUp() - { - object = new LoRaMacCommand(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaMacCommand, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaMacCommand, get_mac_cmd_length) -{ - object->add_link_check_req(); - EXPECT_TRUE(object->get_mac_cmd_length() == 1); - object->clear_command_buffer(); - EXPECT_TRUE(object->get_mac_cmd_length() == 0); -} - -TEST_F(Test_LoRaMacCommand, parse_mac_commands_to_repeat) -{ - loramac_mlme_confirm_t mlme; - lora_mac_system_params_t params; - my_LoRaPHY phy; - uint8_t buf[20]; - - object->parse_mac_commands_to_repeat(); - - buf[0] = 2; - buf[1] = 16; - buf[2] = 32; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 3, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 3; - LoRaPHY_stub::uint8_value = 7; - LoRaPHY_stub::linkAdrNbBytesParsed = 5; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 4; - buf[1] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 5; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 6; - object->set_batterylevel_callback(my_cb); - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 7; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 8; - buf[1] = 0; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 9; - buf[1] = 48; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 10; - buf[1] = 4; - buf[2] = 2; - buf[3] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - object->parse_mac_commands_to_repeat(); -} - -TEST_F(Test_LoRaMacCommand, clear_repeat_buffer) -{ - object->clear_repeat_buffer(); -} - -TEST_F(Test_LoRaMacCommand, copy_repeat_commands_to_buffer) -{ - loramac_mlme_confirm_t mlme; - lora_mac_system_params_t params; - my_LoRaPHY phy; - uint8_t buf[20]; - - object->clear_command_buffer(); - buf[0] = 5; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - object->parse_mac_commands_to_repeat(); - - object->clear_command_buffer(); - EXPECT_TRUE(object->get_mac_cmd_length() == 0); - - object->copy_repeat_commands_to_buffer(); - - EXPECT_TRUE(object->get_mac_cmd_length() != 0); -} - -TEST_F(Test_LoRaMacCommand, get_repeat_commands_length) -{ - EXPECT_TRUE(object->get_repeat_commands_length() == 0); -} - -TEST_F(Test_LoRaMacCommand, clear_sticky_mac_cmd) -{ - loramac_mlme_confirm_t mlme; - lora_mac_system_params_t params; - my_LoRaPHY phy; - uint8_t buf[20]; - - EXPECT_TRUE(object->has_sticky_mac_cmd() == false); - - object->clear_command_buffer(); - buf[0] = 5; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - EXPECT_TRUE(object->has_sticky_mac_cmd() == true); - - object->clear_sticky_mac_cmd(); - EXPECT_TRUE(object->has_sticky_mac_cmd() == false); -} - -TEST_F(Test_LoRaMacCommand, has_sticky_mac_cmd) -{ - loramac_mlme_confirm_t mlme; - lora_mac_system_params_t params; - my_LoRaPHY phy; - uint8_t buf[20]; - - EXPECT_TRUE(object->has_sticky_mac_cmd() == false); - - object->clear_command_buffer(); - buf[0] = 5; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - EXPECT_TRUE(object->has_sticky_mac_cmd() == true); -} - -TEST_F(Test_LoRaMacCommand, process_mac_commands) -{ - loramac_mlme_confirm_t mlme; - lora_mac_system_params_t params; - my_LoRaPHY phy; - uint8_t buf[20]; - EXPECT_TRUE(object->process_mac_commands(NULL, 0, 0, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 2; - buf[1] = 16; - buf[2] = 32; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 3, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - buf[0] = 3; - LoRaPHY_stub::uint8_value = 7; - LoRaPHY_stub::linkAdrNbBytesParsed = 5; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_link_adr_ans function here - object->clear_command_buffer(); - buf[0] = 3; - for (int i = 0; i < 64; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 4; - buf[1] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_duty_cycle_ans() - object->clear_command_buffer(); - for (int i = 0; i < 128; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 5; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_rx_param_setup_ans - object->clear_command_buffer(); - LoRaPHY_stub::uint8_value = 7; - for (int i = 0; i < 64; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 6; - object->set_batterylevel_callback(my_cb); - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //overflow add_dev_status_ans - object->clear_command_buffer(); - for (int i = 0; i < 42; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 7; - buf[1] = 2; - buf[2] = 2; - buf[3] = 2; - buf[4] = 2; - buf[5] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_new_channel_ans - object->clear_command_buffer(); - LoRaPHY_stub::uint8_value = 7; - for (int i = 0; i < 64; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 8; - buf[1] = 0; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_rx_timing_setup_ans - object->clear_command_buffer(); - LoRaPHY_stub::uint8_value = 7; - for (int i = 0; i < 128; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 9; - buf[1] = 48; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_tx_param_setup_ans - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - object->clear_command_buffer(); - LoRaPHY_stub::uint8_value = 7; - for (int i = 0; i < 128; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - LoRaPHY_stub::bool_counter = 0; - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 10; - buf[1] = 4; - buf[2] = 2; - buf[3] = 2; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - - //Overflow add_dl_channel_ans - object->clear_command_buffer(); - for (int i = 0; i < 64; i++) { - EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); - } - EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); - - object->clear_command_buffer(); - buf[0] = 80; - EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_UNSUPPORTED); -} - -TEST_F(Test_LoRaMacCommand, add_link_check_req) -{ - object->add_link_check_req(); - EXPECT_TRUE(object->get_mac_commands_buffer()[0] == 2); - EXPECT_TRUE(object->get_mac_cmd_length() == 1); - object->clear_command_buffer(); - EXPECT_TRUE(object->get_mac_cmd_length() == 0); -} - -TEST_F(Test_LoRaMacCommand, set_batterylevel_callback) -{ - object->set_batterylevel_callback(my_cb); -} - diff --git a/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake b/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake deleted file mode 100644 index a1929ec..0000000 --- a/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake +++ /dev/null @@ -1,41 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaMacCommand") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/mac/LoRaMacCommand.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/mac -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp - stubs/mbed_assert_stub.cpp - stubs/LoRaPHY_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 -) diff --git a/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp b/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp deleted file mode 100644 index 1c00938..0000000 --- a/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaMacCrypto.h" - -#include "cipher_stub.h" -#include "cmac_stub.h" -#include "aes_stub.h" - -class Test_LoRaMacCrypto : public testing::Test { -protected: - LoRaMacCrypto *object; - - virtual void SetUp() - { - cipher_stub.info_value = NULL; - cipher_stub.int_zero_counter = 0; - cipher_stub.int_value = 0; - cmac_stub.int_zero_counter = 0; - cmac_stub.int_value = 0; - aes_stub.int_zero_counter = 0; - aes_stub.int_value = 0; - object = new LoRaMacCrypto(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaMacCrypto, constructor) -{ - EXPECT_TRUE(object); - LoRaMacCrypto obj; -} - -TEST_F(Test_LoRaMacCrypto, compute_mic) -{ - EXPECT_TRUE(MBEDTLS_ERR_CIPHER_ALLOC_FAILED == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - mbedtls_cipher_info_t info; - cipher_stub.info_value = &info; - cipher_stub.int_zero_counter = 0; - cipher_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - cipher_stub.int_value = 0; - cmac_stub.int_zero_counter = 0; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - cmac_stub.int_zero_counter = 1; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - cmac_stub.int_zero_counter = 2; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - cmac_stub.int_zero_counter = 3; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - uint32_t mic[16]; - cmac_stub.int_zero_counter = 3; - cmac_stub.int_value = 0; - EXPECT_TRUE(0 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, mic)); - -} - -TEST_F(Test_LoRaMacCrypto, encrypt_payload) -{ - aes_stub.int_zero_counter = 0; - aes_stub.int_value = -1; - EXPECT_TRUE(-1 == object->encrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); - - aes_stub.int_zero_counter = 1; - aes_stub.int_value = -2; - uint8_t buf[60]; - uint8_t enc[60]; - EXPECT_TRUE(-2 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); - - aes_stub.int_zero_counter = 2; - aes_stub.int_value = -3; - EXPECT_TRUE(-3 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); - - aes_stub.int_value = 0; - EXPECT_TRUE(0 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); - - EXPECT_TRUE(0 == object->encrypt_payload(buf, 60, NULL, 0, 0, 0, 0, enc)); - - aes_stub.int_zero_counter = 0; - EXPECT_TRUE(0 == object->encrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); -} - -TEST_F(Test_LoRaMacCrypto, decrypt_payload) -{ - EXPECT_TRUE(0 == object->decrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); -} - -TEST_F(Test_LoRaMacCrypto, compute_join_frame_mic) -{ - uint32_t mic[16]; - EXPECT_TRUE(MBEDTLS_ERR_CIPHER_ALLOC_FAILED == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); - mbedtls_cipher_info_t info; - cipher_stub.info_value = &info; - cipher_stub.int_zero_counter = 0; - cipher_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); - - cipher_stub.int_value = 0; - cmac_stub.int_zero_counter = 0; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); - - cmac_stub.int_zero_counter = 1; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); - - cmac_stub.int_zero_counter = 2; - cmac_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); - - cmac_stub.int_zero_counter = 3; - cmac_stub.int_value = 0; - EXPECT_TRUE(0 == object->compute_join_frame_mic(NULL, 0, NULL, 0, mic)); -} - -TEST_F(Test_LoRaMacCrypto, decrypt_join_frame) -{ - aes_stub.int_zero_counter = 0; - aes_stub.int_value = -1; - EXPECT_TRUE(-1 == object->decrypt_join_frame(NULL, 0, NULL, 0, NULL)); - - aes_stub.int_zero_counter = 1; - aes_stub.int_value = -1; - EXPECT_TRUE(-1 == object->decrypt_join_frame(NULL, 0, NULL, 0, NULL)); - - aes_stub.int_value = 0; - uint8_t buf[60]; - uint8_t enc[60]; - EXPECT_TRUE(0 == object->decrypt_join_frame(buf, 60, NULL, 0, enc)); -} - -TEST_F(Test_LoRaMacCrypto, compute_skeys_for_join_frame) -{ - uint8_t nwk_key[16]; - uint8_t app_key[16]; - uint8_t nonce[16]; - - aes_stub.int_zero_counter = 0; - aes_stub.int_value = -1; - EXPECT_TRUE(-1 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); - - aes_stub.int_zero_counter = 1; - aes_stub.int_value = -2; - EXPECT_TRUE(-2 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); - - aes_stub.int_zero_counter = 0; - aes_stub.int_value = 0; - EXPECT_TRUE(0 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); -} diff --git a/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake b/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake deleted file mode 100644 index 61aaae9..0000000 --- a/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake +++ /dev/null @@ -1,45 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaMacCrypto") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/mac/LoRaMacCrypto.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/mac -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp - stubs/cipher_stub.c - stubs/aes_stub.c - stubs/cmac_stub.c - stubs/mbed_assert_stub.cpp - ../connectivity/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - ) diff --git a/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp b/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp deleted file mode 100644 index 6220649..0000000 --- a/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp +++ /dev/null @@ -1,944 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHY.h" - -#include "LoRaWANTimer_stub.h" - -class my_LoRaPHY : public LoRaPHY { -public: - my_LoRaPHY() - { - phy_params.adr_ack_delay = 1; - } - - 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 { -protected: - my_LoRaPHY *object; - - virtual void SetUp() - { - object = new my_LoRaPHY(); - memset(&object->get_phy_params(), 0, sizeof(object->get_phy_params())); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaPHY, initialize) -{ - 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; - p[0].dr_range.fields.min = DR_0; - p[0].dr_range.fields.max = DR_5; - object->get_phy_params().channels.channel_list = p; - 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->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; - buf = 0x08; - 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) -{ - 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; - //First 3 channels are set to be default - p.band = 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; - - //Default channel, PARAMETER invalid - EXPECT_TRUE(0 == object->request_new_channel(0, &p)); - - //Freq & DR invalid - p.frequency = 12345; - 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 - p.frequency = 12345; - p.dr_range.fields.max = DR_5; - object->get_phy_params().default_channel_cnt = 3; - EXPECT_TRUE(2 == object->request_new_channel(0, &p)); - - //DR invalid - p.frequency = 8687000; - 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 = DR_5; - p.dr_range.fields.min = DR_0; - uint16_t ch_msk = 0x08; - object->get_phy_params().channels.mask = &ch_msk; - 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]; - memset(list, 0, 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 = 1; - object->get_phy_params().cflist_channel_cnt = 0; - object->get_phy_params().max_channel_cnt = 3; - - uint16_t def_mask = 0x01; - channel_params_t p[16]; - memset(p, 0, 16); - //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->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; - memset(&p, 0, sizeof(rx_config_params_t)); - 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] = 125000; - object->get_phy_params().bandwidths.table = list; - uint8_t list2[1]; - list2[0] = 12; - 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; - memset(&p, 0, sizeof(rx_config_params_t)); - p.frequency = 8687000; - 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; - memset(&b, 0, sizeof(band_t)); - object->get_phy_params().bands.table = &b; - channel_params_t pp; - memset(&pp, 0, sizeof(channel_params_t)); - pp.band = 0; - object->get_phy_params().channels.channel_list = &pp; - uint32_t list[1]; - list[0] = 125000; - object->get_phy_params().bandwidths.table = &list; - uint8_t list2[1]; - list2[0] = 12; - object->get_phy_params().datarates.table = &list2; - my_radio radio; - object->set_radio_instance(radio); - tx_config_params_t p; - memset(&p, 0, sizeof(tx_config_params_t)); - p.channel = 0; - int8_t i = 20; - lorawan_time_t t = 36; - 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; - memset(&p, 0, sizeof(adr_req_params_t)); - uint8_t b[100]; - memset(b, 0, 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 = 0, j = 0; - uint8_t k = 0, l = 0; - uint8_t t[5] = {12, 11, 10, 9, 8}; - t[0] = 0; - object->get_phy_params().datarates.size = 5; - object->get_phy_params().datarates.table = t; - //Test without ADR payload does not make sense here. - - object->get_phy_params().max_channel_cnt = 16; - channel_params_t li[16]; - memset(li, 0, sizeof(channel_params_t) * 16); - 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_trans = 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; - radio.bool_value = true; - object->set_radio_instance(radio); - rx_param_setup_req_t 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) -{ - 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]; - 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; - 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; - - 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; - memset(&p, 0, sizeof(channel_selection_params_t)); - band_t band[1]; - 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; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2)); - - uint16_t list[129]; - memset(list, 0, sizeof(list)); - list[4] = 1; - list[128] = 1; - object->get_phy_params().channels.mask = list; - object->get_phy_params().channels.default_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]; - ch = 5; - t1 = 16; - t2 = 32; - memset(b, 0, sizeof(band_t) * 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; - memset(list, 0, 129); - list[4] = 0; - object->get_phy_params().channels.mask = list; - object->get_phy_params().channels.default_mask = list; - 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; - p.band = 0; - p.frequency = 0; - 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; - b.max_tx_pwr = 10; - 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; - p.tx_power = -1; - p.datarate = 0; - p.antenna_gain = 1; - 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/loraphy/unittest.cmake b/UNITTESTS/features/lorawan/loraphy/unittest.cmake deleted file mode 100644 index 7566576..0000000 --- a/UNITTESTS/features/lorawan/loraphy/unittest.cmake +++ /dev/null @@ -1,46 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHY") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHY.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphy/Test_LoRaPHY.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_WAKEUP_TIME=5 - -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_NB_TRIALS=2 -) - diff --git a/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp b/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp deleted file mode 100644 index 47e9b76..0000000 --- a/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYAS923.h" - -#include "LoRaPHY_stub.h" - -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_LoRaPHYAS923 : public testing::Test { -protected: - LoRaPHYAS923 *object; - my_radio radio; - - virtual void SetUp() - { - LoRaPHY_stub::radio = &radio; - object = new LoRaPHYAS923(); - } - - virtual void TearDown() - { - LoRaPHY_stub::radio = NULL; - delete object; - } -}; - -TEST_F(Test_LoRaPHYAS923, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYAS923, get_alternate_DR) -{ - EXPECT_TRUE(2 == object->get_alternate_DR(1)); -} - -TEST_F(Test_LoRaPHYAS923, set_next_channel) -{ - channel_selection_params_t next_channel; - lorawan_time_t backoff_time = 0; - lorawan_time_t time = 0; - uint8_t ch = 1; - - next_channel.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - next_channel.aggregate_timeoff = 1; - radio.bool_value = false; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - next_channel.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 1; - EXPECT_TRUE(LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - radio.bool_value = true; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); -} - -TEST_F(Test_LoRaPHYAS923, apply_DR_offset) -{ - //0, 1, 2, 3, 4, 5, -1, -2 - for (int i = 0; i < 8; i++) { - uint8_t val = i > 5 ? 5 : 2; - EXPECT_TRUE(object->apply_DR_offset(0, i)); - } -} - diff --git a/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake b/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake deleted file mode 100644 index 723ade1..0000000 --- a/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake +++ /dev/null @@ -1,46 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYAS923") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYAS923.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - diff --git a/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp b/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp deleted file mode 100644 index 93ff3d2..0000000 --- a/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYAU915.h" - -#include "LoRaPHY_stub.h" - -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_LoRaPHYAU915 : public testing::Test { -protected: - LoRaPHYAU915 *object; - my_radio radio; - - virtual void SetUp() - { - LoRaPHY_stub::radio = &radio; - object = new LoRaPHYAU915(); - } - - virtual void TearDown() - { - LoRaPHY_stub::radio = NULL; - delete object; - } -}; - -TEST_F(Test_LoRaPHYAU915, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYAU915, rx_config) -{ - rx_config_params_t p; - memset(&p, 0, sizeof(p)); - - radio.uint8_value = 1; - EXPECT_TRUE(!object->rx_config(&p)); - - radio.uint8_value = 0; - p.is_repeater_supported = true; - EXPECT_TRUE(object->rx_config(&p)); - - p.is_repeater_supported = false; - EXPECT_TRUE(object->rx_config(&p)); -} - -TEST_F(Test_LoRaPHYAU915, tx_config) -{ - tx_config_params_t p; - memset(&p, 0, sizeof(p)); - int8_t tx = 0; - lorawan_time_t time; - p.tx_power = 9; - EXPECT_TRUE(object->tx_config(&p, &tx, &time)); -} - -TEST_F(Test_LoRaPHYAU915, link_ADR_request) -{ - adr_req_params_t params; - memset(¶ms, 0, sizeof(params)); - int8_t dr_out = 0; - int8_t tx_power_out = 0; - uint8_t nb_rep_out = 0; - uint8_t nb_bytes_parsed = 0; - - uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; - params.payload = payload; - params.payload_size = 5; - - LoRaPHY_stub::uint8_value = 1; - LoRaPHY_stub::ch_mask_value = 6; - LoRaPHY_stub::adr_parse_count = 2; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 7; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 5; - LoRaPHY_stub::uint8_value = 6; - EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 66; - LoRaPHY_stub::uint8_value = 7; - EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); -} - -TEST_F(Test_LoRaPHYAU915, accept_rx_param_setup_req) -{ - rx_param_setup_req_t p; - memset(&p, 0, sizeof(p)); - radio.bool_value = false; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 923300000 - 1; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 927500000 + 1; - p.datarate = 6; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 923300000 + 600000; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - LoRaPHY_stub::bool_table[1] = true; - EXPECT_TRUE(7 == object->accept_rx_param_setup_req(&p)); -} - -TEST_F(Test_LoRaPHYAU915, get_alternate_DR) -{ - EXPECT_TRUE(0 == object->get_alternate_DR(0)); - - EXPECT_TRUE(6 == object->get_alternate_DR(1)); -} - -TEST_F(Test_LoRaPHYAU915, set_next_channel) -{ - channel_selection_params_t params; - uint8_t channel; - lorawan_time_t time; - lorawan_time_t timeoff; - - params.current_datarate = 6; - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - radio.bool_value = false; - params.aggregate_timeoff = 1; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 1; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); -} - -TEST_F(Test_LoRaPHYAU915, apply_DR_offset) -{ -// { DR_8, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_0 -// { DR_9, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_1 -// { DR_10, DR_9, DR_8, DR_8, DR_8, DR_8 }, // DR_2 -// { DR_11, DR_10, DR_9, DR_8, DR_8, DR_8 }, // DR_3 -// { DR_12, DR_11, DR_10, DR_9, DR_8, DR_8 }, // DR_4 -// { DR_13, DR_12, DR_11, DR_10, DR_9, DR_8 }, // DR_5 -// { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6 - - for (int i = 0; i < 7; i++) { - for (int j = 0; j < 6; j++) { - uint8_t val = 8 + i; - val -= j; - if (val > 13) { - val = 13; - } - if (val < 8) { - val = 8; - } - EXPECT_TRUE(val == object->apply_DR_offset(i, j)); - } - } -} diff --git a/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake b/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake deleted file mode 100644 index 93c12ac..0000000 --- a/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake +++ /dev/null @@ -1,50 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYAU915") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYAU915.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") - - diff --git a/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp b/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp deleted file mode 100644 index 20e8fc3..0000000 --- a/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYCN470.h" - -#include "LoRaPHY_stub.h" - -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_LoRaPHYCN470 : public testing::Test { -protected: - LoRaPHYCN470 *object; - my_radio radio; - - virtual void SetUp() - { - - LoRaPHY_stub::radio = &radio; - object = new LoRaPHYCN470(); - } - - virtual void TearDown() - { - - LoRaPHY_stub::radio = NULL; - delete object; - } -}; - -TEST_F(Test_LoRaPHYCN470, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYCN470, set_next_channel) -{ - channel_selection_params_t params; - - memset(¶ms, 0, sizeof(params)); - uint8_t channel = 0; - lorawan_time_t time = 0; - lorawan_time_t timeoff = 0; - - params.current_datarate = 4; - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - radio.bool_value = false; - params.aggregate_timeoff = 1; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 1; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); -} - -TEST_F(Test_LoRaPHYCN470, rx_config) -{ - rx_config_params_t p; - memset(&p, 0, sizeof(p)); - - radio.uint8_value = 1; - EXPECT_TRUE(!object->rx_config(&p)); - - radio.uint8_value = 0; - p.is_repeater_supported = true; - EXPECT_TRUE(object->rx_config(&p)); - - p.is_repeater_supported = false; - EXPECT_TRUE(object->rx_config(&p)); -} - -TEST_F(Test_LoRaPHYCN470, tx_config) -{ - tx_config_params_t p; - memset(&p, 0, sizeof(p)); - int8_t tx = 0; - lorawan_time_t time = 0; - p.tx_power = 9; - EXPECT_TRUE(object->tx_config(&p, &tx, &time)); -} - -TEST_F(Test_LoRaPHYCN470, link_ADR_request) -{ - adr_req_params_t params; - memset(¶ms, 0, sizeof(params)); - int8_t dr_out = 0; - int8_t tx_power_out = 0; - uint8_t nb_rep_out = 0; - uint8_t nb_bytes_parsed = 0; - - uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; - params.payload = payload; - params.payload_size = 5; - - LoRaPHY_stub::uint8_value = 1; - LoRaPHY_stub::ch_mask_value = 6; - LoRaPHY_stub::adr_parse_count = 2; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 7; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 5; - LoRaPHY_stub::uint8_value = 6; - EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 66; - LoRaPHY_stub::uint8_value = 7; - EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); -} - -TEST_F(Test_LoRaPHYCN470, accept_rx_param_setup_req) -{ - rx_param_setup_req_t p; - memset(&p, 0, sizeof(p)); - radio.bool_value = false; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 923300000 - 1; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 927500000 + 1; - p.datarate = 6; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); -} - - diff --git a/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake b/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake deleted file mode 100644 index 910ba9a..0000000 --- a/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake +++ /dev/null @@ -1,49 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYCN470") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYCN470.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") - diff --git a/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp b/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp deleted file mode 100644 index 0d729b4..0000000 --- a/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYCN779.h" - -class Test_LoRaPHYCN779 : public testing::Test { -protected: - LoRaPHYCN779 *object; - - virtual void SetUp() - { - object = new LoRaPHYCN779(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaPHYCN779, constructor) -{ - EXPECT_TRUE(object); -} - diff --git a/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake b/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake deleted file mode 100644 index 66c11e2..0000000 --- a/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYCN779") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYCN779.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp - stubs/LoRaPHY_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") diff --git a/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp b/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp deleted file mode 100644 index 1981943..0000000 --- a/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYEU433.h" - -class Test_LoRaPHYEU433 : public testing::Test { -protected: - LoRaPHYEU433 *object; - - virtual void SetUp() - { - object = new LoRaPHYEU433(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaPHYEU433, constructor) -{ - EXPECT_TRUE(object); -} - diff --git a/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake b/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake deleted file mode 100644 index ffafac6..0000000 --- a/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake +++ /dev/null @@ -1,45 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYEU433") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYEU433.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp - stubs/LoRaPHY_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - diff --git a/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp b/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp deleted file mode 100644 index f216c12..0000000 --- a/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYEU868.h" - -class Test_LoRaPHYEU868 : public testing::Test { -protected: - LoRaPHYEU868 *object; - - virtual void SetUp() - { - object = new LoRaPHYEU868(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaPHYEU868, constructor) -{ - EXPECT_TRUE(object); -} - diff --git a/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake b/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake deleted file mode 100644 index 009eb04..0000000 --- a/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake +++ /dev/null @@ -1,45 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYEU868") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYEU868.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp - stubs/LoRaPHY_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - diff --git a/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp b/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp deleted file mode 100644 index ecb1211..0000000 --- a/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYIN865.h" - -class Test_LoRaPHYIN865 : public testing::Test { -protected: - LoRaPHYIN865 *object; - - virtual void SetUp() - { - object = new LoRaPHYIN865(); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaPHYIN865, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYIN865, apply_DR_offset) -{ - EXPECT_TRUE(0 == object->apply_DR_offset(0, 0)); -} - - - diff --git a/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake b/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake deleted file mode 100644 index 1ba6039..0000000 --- a/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake +++ /dev/null @@ -1,45 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYIN865") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYIN865.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp - stubs/LoRaPHY_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - diff --git a/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp b/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp deleted file mode 100644 index 5a170a1..0000000 --- a/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYKR920.h" -#include "LoRaPHY_stub.h" -#include "LoRaRadio.h" - -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) - { - }; - - 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; -}; - -class Test_LoRaPHYKR920 : public testing::Test { -protected: - LoRaPHYKR920 *object; - my_radio radio; - - virtual void SetUp() - { - LoRaPHY_stub::radio = &radio; - object = new LoRaPHYKR920(); - } - - virtual void TearDown() - { - LoRaPHY_stub::radio = NULL; - delete object; - } -}; - -TEST_F(Test_LoRaPHYKR920, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYKR920, verify_frequency_for_band) -{ - radio.bool_value = false; - EXPECT_TRUE(false == object->verify_frequency_for_band(0, 0)); - - radio.bool_value = true; - EXPECT_TRUE(false == object->verify_frequency_for_band(0, 0)); - - EXPECT_TRUE(true == object->verify_frequency_for_band(921100000, 0)); -} - -TEST_F(Test_LoRaPHYKR920, tx_config) -{ - tx_config_params_t tx_config; - memset(&tx_config, 0, sizeof(tx_config)); - int8_t tx_power = 0; - lorawan_time_t time = 0; - - tx_config.tx_power = 9; - EXPECT_TRUE(true == object->tx_config(&tx_config, &tx_power, &time)); -} - -TEST_F(Test_LoRaPHYKR920, set_next_channel) -{ - channel_selection_params_t next_channel; - memset(&next_channel, 0, sizeof(next_channel)); - lorawan_time_t backoff_time = 0; - lorawan_time_t time = 0; - uint8_t ch = 1; - - next_channel.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - next_channel.aggregate_timeoff = 1; - radio.bool_value = false; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - next_channel.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 1; - EXPECT_TRUE(LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); - - radio.bool_value = true; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); -} - -TEST_F(Test_LoRaPHYKR920, set_tx_cont_mode) -{ - cw_mode_params_t params; - memset(¶ms, 0, sizeof(params)); - params.tx_power = 9; - object->set_tx_cont_mode(¶ms, 0); -} - diff --git a/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake b/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake deleted file mode 100644 index a34e3aa..0000000 --- a/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake +++ /dev/null @@ -1,46 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYKR920") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYKR920.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - diff --git a/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp b/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp deleted file mode 100644 index 82d9e7b..0000000 --- a/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaPHYUS915.h" -#include "LoRaPHY_stub.h" - - -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_LoRaPHYUS915 : public testing::Test { -protected: - LoRaPHYUS915 *object; - my_radio radio; - - virtual void SetUp() - { - LoRaPHY_stub::radio = &radio; - object = new LoRaPHYUS915(); - } - - virtual void TearDown() - { - LoRaPHY_stub::radio = NULL; - delete object; - } -}; - -TEST_F(Test_LoRaPHYUS915, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaPHYUS915, restore_default_channels) -{ - object->restore_default_channels(); -} - -TEST_F(Test_LoRaPHYUS915, rx_config) -{ - rx_config_params_t p; - memset(&p, 0, sizeof(p)); - - radio.uint8_value = 1; - EXPECT_TRUE(!object->rx_config(&p)); - - radio.uint8_value = 0; - p.is_repeater_supported = true; - EXPECT_TRUE(object->rx_config(&p)); - - p.is_repeater_supported = false; - EXPECT_TRUE(object->rx_config(&p)); -} - -TEST_F(Test_LoRaPHYUS915, tx_config) -{ - tx_config_params_t p; - memset(&p, 0, sizeof(p)); - int8_t tx = 0; - lorawan_time_t time = 0; - EXPECT_TRUE(object->tx_config(&p, &tx, &time)); -} - -TEST_F(Test_LoRaPHYUS915, link_ADR_request) -{ - uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; - adr_req_params_t params; - memset(¶ms, 0, sizeof(params)); - int8_t dr_out = 0; - int8_t tx_power_out = 0; - uint8_t nb_rep_out = 0; - uint8_t nb_bytes_parsed = 0; - - params.payload = payload; - params.payload_size = 4; - - uint8_t status = object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed); - - EXPECT_TRUE(0 == nb_bytes_parsed); - - params.payload_size = 5; - LoRaPHY_stub::uint8_value = 1; - LoRaPHY_stub::ch_mask_value = 6; - LoRaPHY_stub::adr_parse_count = 2; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 7; - EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 5; - LoRaPHY_stub::uint8_value = 6; - EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); - - LoRaPHY_stub::adr_parse_count = 2; - LoRaPHY_stub::ch_mask_value = 66; - LoRaPHY_stub::uint8_value = 7; - EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); -} - -TEST_F(Test_LoRaPHYUS915, accept_rx_param_setup_req) -{ - rx_param_setup_req_t p; - memset(&p, 0, sizeof(p)); - radio.bool_value = false; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 923300000 - 1; - EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); - - radio.bool_value = true; - p.frequency = 927500000 + 1; - p.datarate = 6; - LoRaPHY_stub::bool_counter = 0; - LoRaPHY_stub::bool_table[0] = true; - EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); -} - -TEST_F(Test_LoRaPHYUS915, get_alternate_DR) -{ - EXPECT_TRUE(0 == object->get_alternate_DR(0)); - - EXPECT_TRUE(4 == object->get_alternate_DR(1)); -} - -TEST_F(Test_LoRaPHYUS915, set_next_channel) -{ - channel_selection_params_t params; - memset(¶ms, 0, sizeof(params)); - uint8_t channel = 0; - lorawan_time_t time = 0; - lorawan_time_t timeoff = 0; - - params.current_datarate = 4; - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - radio.bool_value = false; - params.aggregate_timeoff = 1; - EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); - - params.aggregate_timeoff = 0; - LoRaPHY_stub::uint8_value = 1; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); -} - -TEST_F(Test_LoRaPHYUS915, apply_DR_offset) -{ - //10, 9, 8, 8 - //11, 10, 9, 8 - //12, 11, 10, 9 - //13, 12, 11, 10 - //13, 13, 12, 11 - - for (int i = 0; i < 5; i++) { - for (int j = 0; j < 4; j++) { - uint8_t val = 10 + i; - val -= j; - if (val > 13) { - val = 13; - } - if (val < 8) { - val = 8; - } - EXPECT_TRUE(val == object->apply_DR_offset(i, j)); - } - } -} - -TEST_F(Test_LoRaPHYUS915, set_tx_cont_mode) -{ - cw_mode_params_t p; - memset(&p, 0, sizeof(p)); - object->set_tx_cont_mode(&p, 0); - - p.datarate = 4; - object->set_tx_cont_mode(&p, 0); -} diff --git a/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake b/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake deleted file mode 100644 index d68bca9..0000000 --- a/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake +++ /dev/null @@ -1,48 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaPHYUS915") - -# Source files -set(unittest-sources - ../features/lorawan/lorastack/phy/LoRaPHYUS915.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/lorastack/phy -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/mbed_assert_stub.cpp - -) - -set(unittest-test-flags - -DMBED_CONF_LORA_TX_MAX_SIZE=255 - -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 - -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") diff --git a/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp b/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp deleted file mode 100644 index f4506a8..0000000 --- a/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaWANInterface.h" - -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) - { - }; - - 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) - { - }; - - virtual void start_cad(void) - { - }; - - virtual bool check_rf_frequency(uint32_t frequency) - { - }; - - virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time) - { - }; - - virtual void lock(void) - { - }; - - virtual void unlock(void) - { - }; -}; - -class my_LoRaPHY : public LoRaPHY { -public: - my_LoRaPHY() - { - }; - - virtual ~my_LoRaPHY() - { - }; -}; - -class Test_LoRaWANInterface : public testing::Test { -protected: - LoRaWANInterface *object; - my_radio radio; - - virtual void SetUp() - { - object = new LoRaWANInterface(radio); - } - - virtual void TearDown() - { - delete object; - } -}; - -TEST_F(Test_LoRaWANInterface, constructor) -{ - EXPECT_TRUE(object); - - my_radio radio; - my_LoRaPHY phy; - LoRaWANInterface object(radio, phy); -} - -TEST_F(Test_LoRaWANInterface, initialize) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL)); -} - -TEST_F(Test_LoRaWANInterface, connect) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect()); - - lorawan_connect_t conn; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); -} - -TEST_F(Test_LoRaWANInterface, disconnect) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->disconnect()); -} - -TEST_F(Test_LoRaWANInterface, add_link_check_request) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_link_check_request()); -} - -TEST_F(Test_LoRaWANInterface, remove_link_check_request) -{ - object->remove_link_check_request(); -} - -TEST_F(Test_LoRaWANInterface, set_datarate) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_datarate(1)); -} - -TEST_F(Test_LoRaWANInterface, enable_adaptive_datarate) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->enable_adaptive_datarate()); -} - -TEST_F(Test_LoRaWANInterface, disable_adaptive_datarate) -{ - object->disable_adaptive_datarate(); -} - -TEST_F(Test_LoRaWANInterface, set_confirmed_msg_retries) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_confirmed_msg_retries(1)); -} - -TEST_F(Test_LoRaWANInterface, set_channel_plan) -{ - lorawan_channelplan_t plan; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_channel_plan(plan)); -} - -TEST_F(Test_LoRaWANInterface, get_channel_plan) -{ - lorawan_channelplan_t plan; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_channel_plan(plan)); -} - -TEST_F(Test_LoRaWANInterface, remove_channel_plan) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_channel_plan()); -} - -TEST_F(Test_LoRaWANInterface, remove_channel) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_channel(1)); -} - -TEST_F(Test_LoRaWANInterface, send) -{ - EXPECT_TRUE(0 == object->send(1, NULL, 0, 0)); -} - -TEST_F(Test_LoRaWANInterface, receive) -{ - EXPECT_TRUE(0 == object->receive(1, NULL, 0, 0)); - - uint8_t port; - int flags; - EXPECT_TRUE(0 == object->receive(NULL, 0, port, flags)); -} - -TEST_F(Test_LoRaWANInterface, add_app_callbacks) -{ - lorawan_app_callbacks_t cbs; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_app_callbacks(&cbs)); -} - -TEST_F(Test_LoRaWANInterface, set_device_class) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A)); -} - -TEST_F(Test_LoRaWANInterface, get_tx_metadata) -{ - lorawan_tx_metadata data; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_tx_metadata(data)); -} - -TEST_F(Test_LoRaWANInterface, get_rx_metadata) -{ - lorawan_rx_metadata data; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_rx_metadata(data)); -} - -TEST_F(Test_LoRaWANInterface, get_backoff_metadata) -{ - int i; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_backoff_metadata(i)); -} - -TEST_F(Test_LoRaWANInterface, cancel_sending) -{ - EXPECT_TRUE(LORAWAN_STATUS_OK == object->cancel_sending()); -} - diff --git a/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake b/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake deleted file mode 100644 index 0db5b7a..0000000 --- a/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake +++ /dev/null @@ -1,53 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaWANInterface") - -# Source files -set(unittest-sources - ../features/lorawan/LoRaWANInterface.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaWANStack_stub.cpp - stubs/LoRaMac_stub.cpp - stubs/mbed_assert_stub.cpp - stubs/LoRaMacCrypto_stub.cpp - stubs/LoRaMacChannelPlan_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/LoRaMacCommand_stub.cpp - stubs/LoRaPHYEU868_stub.cpp - stubs/Mutex_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_PHY=EU868 - -DMBED_CONF_LORA_TX_MAX_SIZE=255 -) - - - diff --git a/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp b/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp deleted file mode 100644 index 9fc72b1..0000000 --- a/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaWANStack.h" -#include "events/EventQueue.h" - -#include "LoRaPHY_stub.h" -#include "LoRaMac_stub.h" -#include "equeue_stub.h" -#include "lorawan_data_structures.h" - -static uint8_t batt_level = 0; - -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: - radio_events_t *_ev; - - virtual void init_radio(radio_events_t *events) - { - _ev = 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: - LoRaWANStack *object; - - virtual void SetUp() - { - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - object = new LoRaWANStack(); - } - - virtual void TearDown() - { - delete object; - } -}; - -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)); - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - //Visit callback - if (LoRaMac_stub::_scheduling_failure_handler) { - LoRaMac_stub::_scheduling_failure_handler.call(); - } -} - -void events_cb(lorawan_event_t ev) -{ - -} - -void lc_resp(uint8_t a, uint8_t b) -{ - -} - -uint8_t batt_lvl() -{ - return batt_level; -} - -TEST_F(Test_LoRaWANStack, set_lora_callbacks) -{ - lorawan_app_callbacks_t cb; - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_lora_callbacks(&cb)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_lora_callbacks(NULL)); - - cb.events = NULL; - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_lora_callbacks(&cb)); - - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); -} - -TEST_F(Test_LoRaWANStack, connect) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect()); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; - EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect()); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect()); - - //_ctrl_flags & CONN_IN_PROGRESS_FLAG - EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect()); - - my_radio radio; - my_LoRaPHY 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_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = true; - mlme.req_type = MLME_JOIN; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_value = false; - radio._ev->rx_done(NULL, 0, 0, 0); - - //_ctrl_flags & CONNECTED_FLAG - EXPECT_TRUE(LORAWAN_STATUS_ALREADY_CONNECTED == object->connect()); - - //Visit rx_interrupt_handler's first if - radio._ev->rx_done(NULL, 65535, 0, 0); -} - -TEST_F(Test_LoRaWANStack, connect_args) -{ - lorawan_connect_t conn; - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect(conn)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - conn.connect_type = lorawan_connect_type_t(8); - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->connect(conn)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; - conn.connect_type = LORAWAN_CONNECTION_OTAA; - EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect(conn)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); - - //_ctrl_flags & CONN_IN_PROGRESS_FLAG - EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect(conn)); - - object->shutdown(); - conn.connect_type = LORAWAN_CONNECTION_ABP; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); - - //_ctrl_flags & CONNECTED_FLAG - EXPECT_TRUE(LORAWAN_STATUS_ALREADY_CONNECTED == object->connect(conn)); -} - -TEST_F(Test_LoRaWANStack, add_channels) -{ - lorawan_channelplan_t plan; - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->add_channels(plan)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_channels(plan)); -} - -TEST_F(Test_LoRaWANStack, remove_a_channel) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->remove_a_channel(1)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_a_channel(1)); -} - -TEST_F(Test_LoRaWANStack, drop_channel_list) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->drop_channel_list()); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_confirmed_msg_retry(255)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_channel_data_rate(4)); -} - -TEST_F(Test_LoRaWANStack, enable_adaptive_datarate) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->enable_adaptive_datarate(false)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_tx(0, NULL, 0, 0, false, false)); - - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - 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_link_check_request()); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_NO_ACTIVE_SESSIONS == object->handle_tx(0, NULL, 0, 0, true, false)); - - lorawan_connect_t conn; - conn.connect_type = LORAWAN_CONNECTION_ABP; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); - - LoRaMac_stub::bool_value = false; - EXPECT_TRUE(LORAWAN_STATUS_NO_NETWORK_JOINED == object->handle_tx(0, NULL, 0, 0, true, false)); - - LoRaMac_stub::bool_value = true; - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_tx(0, NULL, 0, 0, true, false)); - - LoRaMac_stub::bool_false_counter = 1; - LoRaMac_stub::bool_value = true; - //set_application_port fails - EXPECT_TRUE(LORAWAN_STATUS_PORT_INVALID == object->handle_tx(0, NULL, 0, 0, true, false)); - - LoRaMac_stub::bool_false_counter = 1; - LoRaMac_stub::bool_value = true; - //Wrong flags -> LORAWAN_STATUS_PARAMETER_INVALID - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_tx(1, NULL, 0, 0x04, true, false)); - - LoRaMac_stub::bool_false_counter = 1; - //Actual sending - EXPECT_TRUE(LORAWAN_STATUS_OK == object->handle_tx(1, NULL, 0, 0x08, 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - 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; - conn.connect_type = LORAWAN_CONNECTION_ABP; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(NULL, 0, port, flags, false)); - - //Prepare ready for receive state - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); - - my_radio radio; - my_LoRaPHY phy; - object->bind_phy_and_radio_driver(radio, phy); - - loramac_mcps_confirm_t conf; - conf.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - ind.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = false; - mlme.req_type = MLME_JOIN; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_value = true; - conf.req_type = MCPS_PROPRIETARY; - - ind.pending = true; - LoRaMac_stub::dev_class_value = CLASS_A; - - loramac_mlme_indication_t mlme_ind; - mlme_ind.pending = false; - LoRaMac_stub::mlme_ind_ptr = &mlme_ind; - - uint8_t ind_buf[150]; - for (int i = 0; i < 110; i++) { - ind_buf[i] = i; - } - ind.buffer = ind_buf; - ind.buffer_size = 150; - ind.type = MCPS_UNCONFIRMED; - ind.port = 15; - ind.is_data_recvd = true; - ind.fpending_status = false; - LoRaMac_stub::dev_class_value = CLASS_A; - radio._ev->rx_done(NULL, 0, 0, 0); - - //data == NULL || LENGTH == 0 (2 cases) - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_rx(NULL, 0, port, flags, false)); - uint8_t data[50]; - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_rx(data, 0, port, flags, false)); - - //validate_params returns Would block - port = 43; - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); - - ind.type = MCPS_CONFIRMED; - radio._ev->rx_done(NULL, 0, 0, 0); - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); - //Call again to visit send_automatic_uplink_message error case - LoRaMac_stub::bool_true_counter = 1; - ind.type = MCPS_CONFIRMED; - ind.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - LoRaMac_stub::bool_value = false; - radio._ev->rx_done(NULL, 0, 0, 0); - - ind.status = LORAMAC_EVENT_INFO_STATUS_OK; - - LoRaMac_stub::bool_value = true; - //convert_to_msg_flag cases - ind.fpending_status = true; - ind.type = MCPS_PROPRIETARY; - radio._ev->rx_done(NULL, 0, 0, 0); - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); - - ind.type = MCPS_MULTICAST; - radio._ev->rx_done(NULL, 0, 0, 0); - EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); - - ind.type = MCPS_UNCONFIRMED; - radio._ev->rx_done(NULL, 0, 0, 0); - - //read not complete - EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); - EXPECT_EQ(10, data[10]); - - EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); - EXPECT_EQ(60, data[10]); - - //read complete - EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); - EXPECT_EQ(100, data[0]); - - //read can fit the buffer - for (int i = 0; i < 110; i++) { - ind_buf[i] = i; - } - ind.buffer = ind_buf; - ind.buffer_size = 50; - ind.type = mcps_type_t(66); - radio._ev->rx_done(NULL, 0, 0, 0); - EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); - EXPECT_EQ(10, data[10]); -} - -TEST_F(Test_LoRaWANStack, set_link_check_request) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_link_check_request()); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_link_check_request()); - - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); - EXPECT_TRUE(LORAWAN_STATUS_OK == 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()); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - EXPECT_TRUE(LORAWAN_STATUS_DEVICE_OFF == object->shutdown()); -} - -TEST_F(Test_LoRaWANStack, set_device_class) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_device_class(CLASS_A)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_UNSUPPORTED == object->set_device_class(CLASS_B)); - - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A)); -} - -TEST_F(Test_LoRaWANStack, acquire_tx_metadata) -{ - lorawan_tx_metadata data; - memset(&data, 0, sizeof(data)); - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_tx_metadata(data)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - // stale = true; - EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_tx_metadata(data)); - - // stale = false; - my_radio radio; - my_LoRaPHY 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; - memset(&conf, 0, sizeof(conf)); - conf.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mcps_conf_ptr = &conf; - 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)); -} - -TEST_F(Test_LoRaWANStack, acquire_rx_metadata) -{ - lorawan_rx_metadata data; - memset(&data, 0, sizeof(data)); - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_rx_metadata(data)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - // stale = true; - EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_rx_metadata(data)); - - // stale = false; - my_radio radio; - my_LoRaPHY 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; - memset(&conf, 0, sizeof(conf)); - conf.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - memset(&ind, 0, sizeof(ind)); - ind.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = true; - mlme.req_type = MLME_JOIN; - - //Visit mlme_confirm_handler here also - mlme.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - LoRaMac_stub::bool_value = false; - radio._ev->rx_done(NULL, 0, 0, 0); - - mlme.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - radio._ev->rx_done(NULL, 0, 0, 0); - - mlme.status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; - LoRaMac_stub::slot_value = RX_SLOT_WIN_2; - radio._ev->rx_done(NULL, 0, 0, 0); - - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); - mlme.req_type = MLME_LINK_CHECK; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_true_counter = true; - radio._ev->rx_done(NULL, 0, 0, 0); - - EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::int_value = 2; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_backoff_metadata(b)); - - LoRaMac_stub::int_value = 0; - EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_backoff_metadata(b)); -} - -TEST_F(Test_LoRaWANStack, stop_sending) -{ - EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->stop_sending()); - - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; - EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->stop_sending()); - - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->stop_sending()); -} - -TEST_F(Test_LoRaWANStack, lock) -{ - object->lock(); -} - -TEST_F(Test_LoRaWANStack, unlock) -{ - object->unlock(); -} - -TEST_F(Test_LoRaWANStack, interrupt_functions) -{ - lorawan_connect_t conn; - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - my_radio radio; - my_LoRaPHY 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_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = true; - mlme.req_type = MLME_JOIN; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_value = false; - radio._ev->rx_done(NULL, 0, 0, 0); - - radio._ev->rx_done(NULL, 0, 0, 0); - - radio._ev->rx_error(); - LoRaMac_stub::slot_value = RX_SLOT_WIN_2; - radio._ev->rx_error(); - - conf.req_type = MCPS_UNCONFIRMED; - LoRaMac_stub::bool_value = true; - radio._ev->rx_error(); - - conf.req_type = MCPS_CONFIRMED; - radio._ev->rx_error(); - - LoRaMac_stub::bool_value = false; - - LoRaMac_stub::slot_value = RX_SLOT_WIN_1; - radio._ev->rx_timeout(); - - radio._ev->tx_timeout(); - - object->shutdown(); - conn.connect_type = LORAWAN_CONNECTION_OTAA; - object->connect(conn); - LoRaMac_stub::status_value = LORAWAN_STATUS_OK; - object->connect(conn); - radio._ev->tx_timeout(); -} - -TEST_F(Test_LoRaWANStack, process_transmission) -{ - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); - - my_radio radio; - my_LoRaPHY phy; - object->bind_phy_and_radio_driver(radio, phy); - - object->connect(); - - struct equeue_event ptr; - equeue_stub.void_ptr = &ptr; - equeue_stub.call_cb_immediately = true; - loramac_mcps_confirm_t conf; - LoRaMac_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = true; - mlme.req_type = MLME_JOIN; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_value = false; - radio._ev->rx_done(NULL, 0, 0, 0); - - LoRaMac_stub::bool_value = true; - conf.req_type = MCPS_PROPRIETARY; - LoRaMac_stub::bool_false_counter = 1; - LoRaMac_stub::dev_class_value = CLASS_A; - object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); - radio._ev->tx_done(); - - LoRaMac_stub::bool_false_counter = 1; - LoRaMac_stub::dev_class_value = CLASS_A; - object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); - radio._ev->tx_done(); - - LoRaMac_stub::bool_false_counter = 1; - LoRaMac_stub::dev_class_value = CLASS_C; - object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); - radio._ev->tx_done(); - - LoRaMac_stub::bool_false_counter = 1; - conf.req_type = MCPS_CONFIRMED; - object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); - radio._ev->tx_done(); -} - -TEST_F(Test_LoRaWANStack, process_reception) -{ - EventQueue queue; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); - - //Prepare ready for receive state - lorawan_app_callbacks_t cb; - cb.events = events_cb; - cb.link_check_resp = lc_resp; - cb.battery_level = batt_lvl; - EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); - - my_radio radio; - my_LoRaPHY 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; - memset(&conf, 0, sizeof(&conf)); - LoRaMac_stub::mcps_conf_ptr = &conf; - radio._ev->tx_done(); - - loramac_mcps_indication_t ind; - memset(&ind, 0, sizeof(ind)); - LoRaMac_stub::mcps_ind_ptr = &ind; - - loramac_mlme_confirm_t mlme; - LoRaMac_stub::mlme_conf_ptr = &mlme; - mlme.pending = false; - mlme.req_type = MLME_JOIN; - mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMac_stub::bool_value = true; - conf.req_type = MCPS_PROPRIETARY; - - ind.pending = true; - LoRaMac_stub::dev_class_value = CLASS_C; - - loramac_mlme_indication_t mlme_ind; - mlme_ind.pending = false; - LoRaMac_stub::mlme_ind_ptr = &mlme_ind; - - uint8_t ind_buf[150]; - for (int i = 0; i < 110; i++) { - ind_buf[i] = i; - } - ind.buffer = ind_buf; - ind.buffer_size = 150; - - //_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED - conf.req_type = MCPS_CONFIRMED; - conf.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - radio._ev->rx_done(NULL, 0, 0, 0); - - ind.is_ack_recvd = false; - LoRaMac_stub::bool_true_counter = 1; - LoRaMac_stub::bool_value = false; - LoRaMac_stub::slot_value = RX_SLOT_WIN_2; - conf.status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; - radio._ev->rx_done(NULL, 0, 0, 0); - - conf.req_type = MCPS_UNCONFIRMED; - LoRaMac_stub::dev_class_value = CLASS_A; - LoRaMac_stub::bool_true_counter++; - mlme_ind.pending = true; - mlme_ind.indication_type = MLME_SCHEDULE_UPLINK; - conf.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - radio._ev->rx_done(NULL, 0, 0, 0); - - ind.is_ack_recvd = true; - conf.req_type = MCPS_CONFIRMED; - conf.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - radio._ev->rx_done(NULL, 0, 0, 0); -} - diff --git a/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake b/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake deleted file mode 100644 index cbedd9c..0000000 --- a/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake +++ /dev/null @@ -1,53 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaWANStack") - -# Source files -set(unittest-sources - ../features/lorawan/LoRaWANStack.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/lorawanstack/Test_LoRaWANStack.cpp - stubs/LoRaPHY_stub.cpp - stubs/LoRaMac_stub.cpp - stubs/mbed_assert_stub.cpp - stubs/mbed_atomic_stub.c - stubs/LoRaMacCrypto_stub.cpp - stubs/LoRaMacChannelPlan_stub.cpp - stubs/LoRaWANTimer_stub.cpp - stubs/LoRaMacCommand_stub.cpp - stubs/EventQueue_stub.cpp - stubs/equeue_stub.c - stubs/Mutex_stub.cpp -) - -set(unittest-test-flags - -DMBED_CONF_LORA_OVER_THE_AIR_ACTIVATION=true - -DMBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE=true - -DMBED_CONF_LORA_TX_MAX_SIZE=255 -) - diff --git a/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp b/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp deleted file mode 100644 index 9fb10a3..0000000 --- a/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018, 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 "gtest/gtest.h" -#include "LoRaWANTimer.h" - -#include "equeue_stub.h" - -using namespace events; - -class Test_LoRaWANTimer : public testing::Test { -protected: - LoRaWANTimeHandler *object; - EventQueue *queue; - - virtual void SetUp() - { - queue = new EventQueue(3, NULL); - object = new LoRaWANTimeHandler(); - object->activate_timer_subsystem(queue); - } - - virtual void TearDown() - { - delete object; - delete queue; - } -}; - -TEST_F(Test_LoRaWANTimer, constructor) -{ - EXPECT_TRUE(object); -} - -TEST_F(Test_LoRaWANTimer, get_current_time) -{ - lorawan_time_t tt = object->get_current_time(); - EXPECT_TRUE(0 == tt); -} - -TEST_F(Test_LoRaWANTimer, get_elapsed_time) -{ - lorawan_time_t tt = object->get_elapsed_time(0); - EXPECT_TRUE(0 == tt); -} - -void my_callback() -{ -} - -TEST_F(Test_LoRaWANTimer, init) -{ - timer_event_t ev; - memset(&ev, 0, sizeof(ev)); - object->init(ev, my_callback); -} - -TEST_F(Test_LoRaWANTimer, start) -{ - equeue_stub.void_ptr = NULL; - timer_event_t ev; - memset(&ev, 0, sizeof(ev)); - object->start(ev, 10); -} - -TEST_F(Test_LoRaWANTimer, stop) -{ - timer_event_t ev; - memset(&ev, 0, sizeof(ev)); - ev.timer_id = 4; - object->stop(ev); - EXPECT_TRUE(ev.timer_id == 0); -} - - - diff --git a/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake b/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake deleted file mode 100644 index b4ee1c9..0000000 --- a/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake +++ /dev/null @@ -1,44 +0,0 @@ -#[[ - * Copyright (c) 2018, 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. -]] - -# Unit test suite name -set(TEST_SUITE_NAME "lorawan_LoRaWANTimer") - -# Source files -set(unittest-sources - ../features/lorawan/system/LoRaWANTimer.cpp -) - -# Add test specific include paths -set(unittest-includes ${unittest-includes} - target_h - ../features/lorawan/system -) - -# Test & stub files -set(unittest-test-sources - features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp - stubs/EventQueue_stub.cpp - stubs/mbed_assert_stub.cpp - stubs/equeue_stub.c -) - -set(unittest-test-flags - -DNDEBUG=1 - -DMBED_CONF_LORA_TX_MAX_SIZE=255 -) - diff --git a/connectivity/lorawan/FSB_Usage.txt b/connectivity/lorawan/FSB_Usage.txt new file mode 100644 index 0000000..ef0706a --- /dev/null +++ b/connectivity/lorawan/FSB_Usage.txt @@ -0,0 +1,52 @@ +Frequency sub-bands in US915/AU915: + + US915/AU915 PHYs define channel structures that can support up to 72 channels for upstream. + The first 64 channels (0-63), occupy 125 kHz and the last 8 channels (64-71) occupy 500 kHz. + However, most of the base stations available in the market support 8 or 16 channels. + Network acquisition can become costly if the device has no prior knowledge of the active channel plan and it enables + all 72 channels to begin with. + + The LoRaWAN 1.0.2 Regional parameters specification refers to a strategy of probing a set of nine channels (8 + 1) for + the joining process. According to that strategy, the device alternatively selects a channel from a set of + 8 125 kHz channels and a 500 kHz channel. + For example, send a join request alternatively on a randomly selected channel from a set of 0-7 channels and + channel 64, which is the first 500 kHz channel. + + Once the device has joined the network (in case of OTAA) or has sent the first uplink (in the case of ABP), the network + may send a LinkAdrReq MAC command to set the channel mask to be used. Please note that these PHY layers do not + support CFList, so LinkAdrReq is the way the network tells you what channel plan to use. + + You can configure the Mbed LoRaWAN stack to use a particular frequency sub-band (FSB), which means that you don't have to + probe all sets of channels. "fsb-mask" in lorawan/mbed_lib.json is the parameter that you can use to tell the + system which FSB or set of FSBs to use. By default, the "fsb-mask" is set to "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}". + That means all channels are active. In other words, 64 125 kHz channels and 8 500 kHz channels are active. If you wish + to use a custom FSB, you need to set an appropriate mask as the value of "fsb-mask". For example, if you wish to use the + first FSB, in other words, the first 8 125 kHz channels (0-7) and the first 500 kHz channel: + "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0001}" + Similarly, if you wish to use the second FSB, in other words, the second set of 8 125 kHz channels (8-15) and the 2nd 500 kHz + channel: + "fsb-mask" = "{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}" + + You can also combine FSBs if your base station supports more than 8 channels. For example: + "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0xFF00, 0x0081}" + means use channels 0-7(125 kHz) + channel 64 (500 KHz) and channels 56-63 (125 kHz) + channel 71 (500 kHz). + + Please note that for Certification requirements, you need to alternate between 125 kHz and 500 kHz channels, so before joining, + do not set a mask that enables only 500 kHz or only 125 kHz channels. + + Frequency sub-bands in CN470 PHY: + + The LoRaPHYCN470 class defines 96 channels in total, as per the LoRaWAN Regional Specification. These 96 channels + are 125 kHz wide each and can be subdivided into 6 sub-bands containing 16 channels each. + "fsb-mask-china" is the parameter that lorawan/mbed_lib.json defines. It can be used to enforce an FSB. It is defined + as a C-style array, and the first element of the array corresponds to first 8 channels (0-7) and so on. By default, all + 96 channels are enabled, but there may be base stations that do not support all 96 channels. Therefore, network acquisition + can become cumbersome if the device hops on random channels. The probability of finding a correct channel for a base station + that supports 8 channels would be 1/12. + + For example, if your base station supports 16 channels (channels 0-15), set the "fsb-mask-china" as: + "fsb-mask-china" = "{0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}" + + Similarly, if your base station supports 8 channels (channels 0-7), set the "fsb-mask-china" as: + "fsb-mask-china" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}" + diff --git a/connectivity/lorawan/LICENSE b/connectivity/lorawan/LICENSE new file mode 100644 index 0000000..d6dfb1b --- /dev/null +++ b/connectivity/lorawan/LICENSE @@ -0,0 +1,25 @@ +--- Revised BSD License --- +Copyright (c) 2013, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/connectivity/lorawan/LoRaRadio.h b/connectivity/lorawan/LoRaRadio.h new file mode 100644 index 0000000..601c6b9 --- /dev/null +++ b/connectivity/lorawan/LoRaRadio.h @@ -0,0 +1,667 @@ +/** + * Copyright (c) 2017, 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. + */ + +#ifndef LORARADIO_H_ +#define LORARADIO_H_ + +/** @addtogroup LoRaWAN + * Parent class for a LoRa radio driver + * @{ + */ + +#include "platform/Callback.h" +#include "PinNames.h" + +/** + * Structure to hold RF controls for LoRa Radio. + * SX1276 have an extra control for the crystal (used in DISCO-L072CZ). + * A subset of these pins may be used by the driver in accordance with the physical + * implementation. + */ +typedef struct { + /** TX latch switch pin. + * Exact operation is implementation specific. + */ + PinName rf_switch_ctl1; + + /** RX latch switch pin. + * Exact operation is implementation specific. + */ + PinName rf_switch_ctl2; + + /** TX control pin for transceiver packaged as a module. + * Exact operation is implementation specific. + */ + PinName txctl; + + /** RX control pin for transceiver packaged as a module. + * Exact operation is implementation specific. + */ + PinName rxctl; + + /** Transceiver switch pin. + * Exact operation is implementation specific. One of the polarities of the + * pin may drive the transceiver in either TX or RX mode. + */ + PinName ant_switch; + + /** Power amplifier control pin. + * Exact operation is implementation specific. If defined, + * controls the operation of an external power amplifier. + */ + PinName pwr_amp_ctl; + + /** TCXO crystal control pin. + * Exact operation is implementation specific. + */ + PinName tcxo; +} rf_ctrls; + +/** Radio driver internal state. + * Helps identify current state of the transceiver. + */ +typedef enum radio_state { + /** IDLE state. + * Radio is in idle state. + */ + RF_IDLE = 0, + + /** RX state. + * Radio is receiving. + */ + RF_RX_RUNNING, + + /** TX state. + * Radio is transmitting. + */ + RF_TX_RUNNING, + + /** CAD state. + * Radio is detecting channel activity. + */ + RF_CAD, +} radio_state_t; + +/** Type of modem. + * [LORA/FSK] + */ +typedef enum modem_type { + /** FSK operation mode. + * Radio is using FSK modulation. + */ + MODEM_FSK = 0, + + /** LoRa operation mode. + * Radio is using LoRa modulation. + */ + MODEM_LORA +} radio_modems_t; + +/** FSK modem parameters. + * Parameters encompassing FSK modulation. + */ +typedef struct radio_fsk_settings { + /** + * Transmit power. + */ + int8_t power; + + /** + * Frequency deviation. + */ + uint32_t f_dev; + + /** + * Modulation bandwidth. + */ + uint32_t bandwidth; + + /** + * Automated frequency correction bandwidth. + */ + uint32_t bandwidth_afc; + + /** + * Data rate (SF). + */ + uint32_t datarate; + + /** + * Expected preamble length. + */ + uint16_t preamble_len; + + /** + * This flag turns on if the TX data size is fixed. + */ + bool fix_len; + + /** + * Size of outgoing data. + */ + uint8_t payload_len; + + /** + * Turn CRC on/off. + */ + bool crc_on; + + /** @deprecated + * Does not apply to FSK. Will be removed. + */ + bool iq_inverted; + + /** + * Turn continuous reception mode (such as Class C mode) on/off. + */ + bool rx_continuous; + + /** + * Timeout value in milliseconds (ms) after which the radio driver reports + * a timeout if the radio was unable to transmit. + */ + uint32_t tx_timeout; + + /** + * Timeout value in symbols (symb) after which the radio driver reports a timeout + * if the radio did not receive a Preamble. + */ + uint32_t rx_single_timeout; +} radio_fsk_settings_t; + +/** FSK packet handle. + * Contains information about an FSK packet and various metadata. + */ +typedef struct radio_fsk_packet_handler { + /** + * Set to true (1) when a Preamble is detected, otherwise false (0). + */ + uint8_t preamble_detected; + + /** + * Set to true (1) when a SyncWord is detected, otherwise false (0). + */ + uint8_t sync_word_detected; + + /** + * Storage for RSSI value of the received signal. + */ + int8_t rssi_value; + + /** + * Automated frequency correction value. + */ + int32_t afc_value; + + /** + * LNA gain value (dbm). + */ + uint8_t rx_gain; + + /** + * Size of the received data in bytes. + */ + uint16_t size; + + /** + * Keeps track of number of bytes already read from the RX FIFO. + */ + uint16_t nb_bytes; + + /** + * Stores the FIFO threshold value. + */ + uint8_t fifo_thresh; + + /** + * Defines the size of a chunk of outgoing buffer written to + * the FIFO at a unit time. For example, if the size of the data exceeds the FIFO + * limit, a certain sized chunk is written to the FIFO. Later, a FIFO-level + * interrupt enables writing of the remaining data to the FIFO chunk by chunk until + * transmission is complete. + */ + uint8_t chunk_size; +} radio_fsk_packet_handler_t; + +/** LoRa modem parameters. + * Parameters encompassing LoRa modulation. + */ +typedef struct radio_lora_settings { + /** + * Transmit power. + */ + int8_t power; + + /** + * Modulation bandwidth. + */ + uint32_t bandwidth; + + /** + * Data rate (SF). + */ + uint32_t datarate; + + /** + * Turn low data rate optimization on/off. + */ + bool low_datarate_optimize; + + /** + * Error correction code rate. + */ + uint8_t coderate; + + /** + * Preamble length in symbols. + */ + uint16_t preamble_len; + + /** + * Set to true if the outgoing payload length is fixed. + */ + bool fix_len; + + /** + * Size of outgoing payload. + */ + uint8_t payload_len; + + /** + * Turn CRC on/off. + */ + bool crc_on; + + /** + * Turn frequency hopping on/off. + */ + bool freq_hop_on; + + /** + * Number of symbols between two frequency hops. + */ + uint8_t hop_period; + + /** + * Turn IQ inversion on/off. Usually, the end device sends an IQ inverted + * signal, and the base stations do not invert. We recommended sending an + * IQ inverted signal from the device side, so any transmissions from the + * base stations do not interfere with end device transmission. + */ + bool iq_inverted; + + /** + * Turn continuous reception mode (such as in Class C) on/off. + */ + bool rx_continuous; + + /** + * Timeout in milliseconds (ms) after which the radio driver reports an error + * if the radio was unable to transmit. + */ + uint32_t tx_timeout; + + /** + * Change the network mode to Public or Private. + */ + bool public_network; +} radio_lora_settings_t; + +/** LoRa packet + * Contains information about a LoRa packet. + */ +typedef struct radio_lora_packet_handler { + /** + * Signal-to-noise ratio of a received packet. + */ + int8_t snr_value; + + /** + * RSSI value in dBm for the received packet. + */ + int8_t rssi_value; + + /** + * Size of the transmitted or received packet. + */ + uint8_t size; +} radio_lora_packet_handler_t; + +/** Global radio settings. + * Contains settings for the overall transceiver operation. + */ +typedef struct radio_settings { + /** + * Current state of the radio, such as RF_IDLE. + */ + uint8_t state; + + /** + * Current modem operation, such as MODEM_LORA. + */ + uint8_t modem; + + /** + * Current channel of operation. + */ + uint32_t channel; + + /** + * Settings for FSK modem part. + */ + radio_fsk_settings_t fsk; + + /** + * FSK packet and meta data. + */ + radio_fsk_packet_handler_t fsk_packet_handler; + + /** + * Settings for LoRa modem part. + */ + radio_lora_settings_t lora; + + /** + * LoRa packet and metadata. + */ + radio_lora_packet_handler_t lora_packet_handler; +} radio_settings_t; + +/** Reporting functions for upper layers. + * The radio driver reports various vital events to the upper controlling layers + * using callback functions provided by the upper layers at the initialization + * phase. + */ +typedef struct radio_events { + /** + * Callback when Transmission is done. + */ + mbed::Callback tx_done; + + /** + * Callback when Transmission is timed out. + */ + mbed::Callback tx_timeout; + + /** + * Rx Done callback prototype. + * + * @param payload Received buffer pointer. + * @param size Received buffer size. + * @param rssi RSSI value computed while receiving the frame [dBm]. + * @param snr Raw SNR value given by the radio hardware. + * FSK : N/A (set to 0) + * LoRa: SNR value in dB + */ + mbed::Callback rx_done; + + /** + * Callback when Reception is timed out. + */ + mbed::Callback rx_timeout; + + /** + * Callback when Reception ends up in error. + */ + mbed::Callback rx_error; + + /** + * FHSS Change Channel callback prototype. + * + * @param current_channel The index number of the current channel. + */ + mbed::Callback fhss_change_channel; + + /** + * CAD Done callback prototype. + * + * @param channel_busy True, if Channel activity detected. + */ + mbed::Callback cad_done; +} radio_events_t; + +/** + * Interface for the radios, containing the main functions that a radio needs, and five callback functions. + */ +class LoRaRadio { + +public: + + /** + * Registers radio events with the Mbed LoRaWAN stack and undergoes initialization steps, if any. + * + * @param events Contains driver callback functions. + */ + virtual void init_radio(radio_events_t *events) = 0; + + /** + * Resets the radio module. + */ + virtual void radio_reset() = 0; + + /** + * Put the RF module in sleep mode. + */ + virtual void sleep(void) = 0; + + /** + * Sets the radio to standby mode. + */ + virtual void standby(void) = 0; + + /** + * Sets reception parameters. + * + * @param modem The radio modem [0: FSK, 1: LoRa]. + * @param bandwidth Sets the bandwidth. + * FSK : >= 2600 and <= 250000 Hz + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param datarate Sets the datarate. + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param coderate Sets the coding rate (LoRa only). + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param bandwidth_afc Sets the AFC bandwidth (FSK only). + * FSK : >= 2600 and <= 250000 Hz + * LoRa: N/A (set to 0) + * @param preamble_len Sets the preamble length (LoRa only). + * FSK : N/A (set to 0) + * LoRa: Length in symbols (the hardware adds four more symbols). + * @param symb_timeout Sets the RxSingle timeout value. + * FSK : Timeout number of bytes + * LoRa: Timeout in symbols + * @param fix_len Fixed length packets [0: variable, 1: fixed]. + * @param payload_len Sets the payload length when fixed length is used. + * @param crc_on Enables/disables CRC [0: OFF, 1: ON]. + * @param freq_hop_on Enables/disables intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only). + * @param hop_period The number of symbols bewteen each hop (LoRa only). + * @param iq_inverted Inverts the IQ signals (LoRa only). + * FSK : N/A (set to 0) + * LoRa: [0: not inverted, 1: inverted] + * @param rx_continuous Sets the reception to continuous mode. + * [false: single mode, true: continuous mode] + */ + 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) = 0; + + /** + * Sets the transmission parameters. + * + * @param modem The radio modem [0: FSK, 1: LoRa]. + * @param power Sets the output power [dBm]. + * @param fdev Sets the frequency deviation (FSK only). + * FSK : [Hz] + * LoRa: 0 + * @param bandwidth Sets the bandwidth (LoRa only). + * FSK : 0 + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param datarate Sets the datarate. + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param coderate Sets the coding rate (LoRa only). + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param preamble_len Sets the preamble length. + * @param fix_len Fixed length packets [0: variable, 1: fixed]. + * @param crc_on Enables/disables CRC [0: OFF, 1: ON]. + * @param freq_hop_on Enables/disables intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only). + * @param hop_period The number of symbols between each hop (LoRa only). + * @param iq_inverted Inverts IQ signals (LoRa only) + * FSK : N/A (set to 0). + * LoRa: [0: not inverted, 1: inverted] + * @param timeout The transmission timeout [ms]. + */ + 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) = 0; + + /** + * Sends the packet. + * + * Prepares the packet to be sent and sets the radio to transmission mode. + * + * @param buffer A pointer to the buffer. + * @param size The buffer size. + */ + virtual void send(uint8_t *buffer, uint8_t size) = 0; + + /** + * Sets the radio to reception mode. + * + * To configure the receiver, use the `set_rx_config()` API. + */ + virtual void receive(void) = 0; + + /** + * Sets the carrier frequency. + * + * @param freq Channel RF frequency. + */ + virtual void set_channel(uint32_t freq) = 0; + + /** + * Generates a 32 bit random value based on RSSI readings. + * + * \remark This function sets the radio in LoRa modem mode and disables all interrupts. + * After calling this function, either `Radio.SetRxConfig` or + * `Radio.SetTxConfig` functions must be called. + * + * @return A 32 bit random value. + */ + virtual uint32_t random(void) = 0; + + /** + * Gets the radio status. + * + * @return The current radio status. + */ + virtual uint8_t get_status(void) = 0; + + /** + * Sets the maximum payload length. + * + * @param modem The radio modem [0: FSK, 1: LoRa]. + * @param max The maximum payload length in bytes. + */ + virtual void set_max_payload_length(radio_modems_t modem, uint8_t max) = 0; + + /** + * Sets the network to public or private. + * + * Updates the sync byte. Applies to LoRa modem only. + * + * @param enable If true, enables a public network. + */ + virtual void set_public_network(bool enable) = 0; + + /** + * Computes the packet time on air for the given payload. + * + * \remark This can only be called after `SetRxConfig` or `SetTxConfig`. + * + * @param modem The radio modem [0: FSK, 1: LoRa]. + * @param pkt_len The packet payload length. + * @return The computed `airTime` for the given packet payload length. + */ + virtual uint32_t time_on_air(radio_modems_t modem, uint8_t pkt_len) = 0; + + /** + * Performs carrier sensing. + * + * Checks for a certain time if the RSSI is above a given threshold. + * This threshold determines whether or not there is a transmission on + * the channel already. + * + * @param modem The type of radio modem. + * @param freq The carrier frequency. + * @param rssi_threshold The threshold value of RSSI. + * @param max_carrier_sense_time The time set for sensing the channel (ms). + * + * @return True if there is no active transmission + * in the channel, otherwise false. + */ + virtual bool perform_carrier_sense(radio_modems_t modem, + uint32_t freq, + int16_t rssi_threshold, + uint32_t max_carrier_sense_time) = 0; + + /** + * Sets the radio to CAD mode. + * + */ + virtual void start_cad(void) = 0; + + /** + * Checks whether the given RF is in range. + * + * @param frequency The frequency to check. + */ + virtual bool check_rf_frequency(uint32_t frequency) = 0; + + /** Sets the radio to continuous wave transmission mode. + * + * @param freq The RF frequency of the channel. + * @param power The output power [dBm]. + * @param time The transmission mode timeout [s]. + */ + virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time) = 0; + + /** + * Acquires exclusive access to this radio. + */ + virtual void lock(void) = 0; + + /** + * Releases exclusive access to this radio. + */ + virtual void unlock(void) = 0; +}; + +#endif // LORARADIO_H_ +/** @}*/ diff --git a/connectivity/lorawan/LoRaWANBase.h b/connectivity/lorawan/LoRaWANBase.h new file mode 100644 index 0000000..5ab910d --- /dev/null +++ b/connectivity/lorawan/LoRaWANBase.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2017, 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. + */ + +#ifndef LORAWANBASE_H_ +#define LORAWANBASE_H_ + +/** + * This class is deprecated and will be removed altogether after expiration of + * deprecation notice. + */ +#include "LoRaWANInterface.h" + +MBED_DEPRECATED_SINCE("mbed-os-5.12", "Migrated to LoRaWANInterface") +typedef LoRaWANInterface LoRaWANBase; + +#endif /* LORAWANBASE_H_ */ diff --git a/connectivity/lorawan/LoRaWANInterface.cpp b/connectivity/lorawan/LoRaWANInterface.cpp new file mode 100644 index 0000000..f748fbf --- /dev/null +++ b/connectivity/lorawan/LoRaWANInterface.cpp @@ -0,0 +1,186 @@ +/** + * @file + * + * @brief A LoRaWAN network interface + * + * Copyright (c) 2017, 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 "LoRaWANInterface.h" +#include "lorastack/phy/loraphy_target.h" +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "LSTK" + +using namespace mbed; +using namespace events; + +LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio) + : _default_phy(NULL) +{ + _default_phy = new LoRaPHY_region; + MBED_ASSERT(_default_phy); + _lw_stack.bind_phy_and_radio_driver(radio, *_default_phy); +} + +LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio, LoRaPHY &phy) + : _default_phy(NULL) +{ + _lw_stack.bind_phy_and_radio_driver(radio, phy); +} + +LoRaWANInterface::~LoRaWANInterface() +{ + delete _default_phy; + _default_phy = NULL; +} + +lorawan_status_t LoRaWANInterface::initialize(EventQueue *queue) +{ + Lock lock(*this); + return _lw_stack.initialize_mac_layer(queue); +} + +lorawan_status_t LoRaWANInterface::connect() +{ + Lock lock(*this); + return _lw_stack.connect(); +} + +lorawan_status_t LoRaWANInterface::connect(const lorawan_connect_t &connect) +{ + Lock lock(*this); + return _lw_stack.connect(connect); +} + +lorawan_status_t LoRaWANInterface::disconnect() +{ + Lock lock(*this); + return _lw_stack.shutdown(); +} + +lorawan_status_t LoRaWANInterface::add_link_check_request() +{ + Lock lock(*this); + return _lw_stack.set_link_check_request(); +} + +void LoRaWANInterface::remove_link_check_request() +{ + Lock lock(*this); + _lw_stack.remove_link_check_request(); +} + +lorawan_status_t LoRaWANInterface::set_datarate(uint8_t data_rate) +{ + Lock lock(*this); + return _lw_stack.set_channel_data_rate(data_rate); +} + +lorawan_status_t LoRaWANInterface::set_confirmed_msg_retries(uint8_t count) +{ + Lock lock(*this); + return _lw_stack.set_confirmed_msg_retry(count); +} + +lorawan_status_t LoRaWANInterface::enable_adaptive_datarate() +{ + Lock lock(*this); + return _lw_stack.enable_adaptive_datarate(true); +} + +lorawan_status_t LoRaWANInterface::disable_adaptive_datarate() +{ + Lock lock(*this); + return _lw_stack.enable_adaptive_datarate(false); +} + +lorawan_status_t LoRaWANInterface::set_channel_plan(const lorawan_channelplan_t &channel_plan) +{ + Lock lock(*this); + return _lw_stack.add_channels(channel_plan); +} + +lorawan_status_t LoRaWANInterface::get_channel_plan(lorawan_channelplan_t &channel_plan) +{ + Lock lock(*this); + return _lw_stack.get_enabled_channels(channel_plan); +} + +lorawan_status_t LoRaWANInterface::remove_channel(uint8_t id) +{ + Lock lock(*this); + return _lw_stack.remove_a_channel(id); +} + +lorawan_status_t LoRaWANInterface::remove_channel_plan() +{ + Lock lock(*this); + return _lw_stack.drop_channel_list(); +} + +int16_t LoRaWANInterface::send(uint8_t port, const uint8_t *data, uint16_t length, int flags) +{ + Lock lock(*this); + return _lw_stack.handle_tx(port, data, length, flags); +} + +lorawan_status_t LoRaWANInterface::cancel_sending(void) +{ + Lock lock(*this); + return _lw_stack.stop_sending(); +} + +lorawan_status_t LoRaWANInterface::get_tx_metadata(lorawan_tx_metadata &metadata) +{ + Lock lock(*this); + return _lw_stack.acquire_tx_metadata(metadata); +} + +lorawan_status_t LoRaWANInterface::get_rx_metadata(lorawan_rx_metadata &metadata) +{ + Lock lock(*this); + return _lw_stack.acquire_rx_metadata(metadata); +} + +lorawan_status_t LoRaWANInterface::get_backoff_metadata(int &backoff) +{ + Lock lock(*this); + return _lw_stack.acquire_backoff_metadata(backoff); +} + +int16_t LoRaWANInterface::receive(uint8_t port, uint8_t *data, uint16_t length, int flags) +{ + Lock lock(*this); + return _lw_stack.handle_rx(data, length, port, flags, true); +} + +int16_t LoRaWANInterface::receive(uint8_t *data, uint16_t length, uint8_t &port, int &flags) +{ + Lock lock(*this); + return _lw_stack.handle_rx(data, length, port, flags, false); +} + +lorawan_status_t LoRaWANInterface::add_app_callbacks(lorawan_app_callbacks_t *callbacks) +{ + Lock lock(*this); + return _lw_stack.set_lora_callbacks(callbacks); +} + +lorawan_status_t LoRaWANInterface::set_device_class(const device_class_t device_class) +{ + Lock lock(*this); + return _lw_stack.set_device_class(device_class); +} diff --git a/connectivity/lorawan/LoRaWANInterface.h b/connectivity/lorawan/LoRaWANInterface.h new file mode 100644 index 0000000..a55d80f --- /dev/null +++ b/connectivity/lorawan/LoRaWANInterface.h @@ -0,0 +1,577 @@ +/** + * Copyright (c) 2017, 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. + */ + +/** @addtogroup LoRaWAN + * Mbed OS LoRaWAN Stack + * @{ + */ + +#ifndef LORAWANINTERFACE_H_ +#define LORAWANINTERFACE_H_ + +#include "platform/Callback.h" +#include "platform/ScopedLock.h" +#include "events/EventQueue.h" +#include "LoRaWANStack.h" +#include "LoRaRadio.h" +#include "lorawan_types.h" + +// Forward declaration of LoRaPHY class +class LoRaPHY; + +/** LoRaWANInterface Class + * A network interface for LoRaWAN + */ +class LoRaWANInterface { + +public: + + /** Constructs a LoRaWANInterface using the LoRaWANStack instance underneath. + * + * Currently, LoRaWANStack is a singleton and you should only + * construct a single instance of LoRaWANInterface. + * + * LoRaWANInterface will construct PHY based on "lora.phy" setting in mbed_app.json. + * + * @param radio A reference to radio object + */ + LoRaWANInterface(LoRaRadio &radio); + + /** Constructs a LoRaWANInterface using the user provided PHY object. + + * @param radio A reference to radio object + * @param phy A reference to PHY object + */ + LoRaWANInterface(LoRaRadio &radio, LoRaPHY &phy); + + ~LoRaWANInterface(); + + /** Initialize the LoRa stack. + * + * You must call this before using the LoRa stack. + * + * @param queue A pointer to EventQueue provided by the application. + * + * @return LORAWAN_STATUS_OK on success, a negative error code on failure: + * LORAWAN_STATUS_PARAMETER_INVALID is NULL queue is given. + */ + lorawan_status_t initialize(events::EventQueue *queue); + + /** Connect OTAA or ABP using the Mbed OS config system + * + * Connect by Over The Air Activation or Activation By Personalization. + * You need to configure the connection properly using the Mbed OS configuration system. + * + * When connecting through OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) + * is negative. However, this is not a real error. It tells you that the connection is in progress, + * and an event will notify you of the completion. By default, after the Join Accept message is + * received, base stations may provide the node with a CF-List that replaces all user-configured + * channels except the Join/Default channels. A CF-List can configure a maximum of five channels + * other than the default channels. + * + * To configure more channels, we recommend that you use the `set_channel_plan()` API after the connection. + * By default, the PHY layers configure only the mandatory Join channels. The retransmission back-off + * restrictions on these channels are severe, and you may experience long delays or even failures + * in the confirmed traffic. If you add more channels, the aggregated duty cycle becomes much more + * relaxed as compared to the Join (default) channels only. + * + * **NOTES ON RECONNECTION:** + * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile memory storage. + * Therefore, the state and frame counters cannot be restored after a power cycle. However, + * if you use the `disconnect()` API to shut down the LoRaWAN protocol, the state and frame + * counters are saved. Connecting again restores the previous session. According to the LoRaWAN + * 1.0.2 specification, the frame counters are always reset to 0 for OTAA, and a new Join request + * lets the network server know that the counters need a reset. The same is said about the ABP, + * but there is no way to convey this information to the network server. For a network server, + * an ABP device is always connected. That's why storing the frame counters is important for ABP. + * That's why we restore frame counters from session information after a disconnection. + * + * @return Common: LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if connection parameters are invalid. + * + * For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call + * followed by a 'CONNECTED' event. Otherwise a negative error code is returned: + * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. + * + * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for + * the first call. Any subsequent call will return either LORAWAN_STATUS_BUSY + * (if the previous request for connection is still underway) or + * LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). + * A 'CONNECTED' event is sent to the application when the JoinAccept is received. + */ + lorawan_status_t connect(); + + /** Connect OTAA or ABP with parameters + * + * All connection parameters are chosen by you and provided in the data structure passed down. + * + * When connecting using OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) + * is negative. However, this is not a real error. It tells you that connection is in progress, + * and an event will notify you of completion. By default, after Join Accept message is received, + * base stations may provide the node with a CF-List that replaces all user-configured channels + * except the Join/Default channels. A CF-List can configure a maximum of five channels other + * than the default channels. + * + * To configure more channels, we recommend that you use the `set_channel_plan()` API after + * the connection. By default, the PHY layers configure only the mandatory Join channels. + * The retransmission back-off restrictions on these channels are severe, and you may experience + * long delays or even failures in the confirmed traffic. If you add more channels, the aggregated + * duty cycle becomes much more relaxed as compared to the Join (default) channels only. + * + * **NOTES ON RECONNECTION:** + * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile memory storage. + * Therefore, the state and frame counters cannot be restored after a power cycle. However, + * if you use the `disconnect()` API to shut down the LoRaWAN protocol, the state and frame + * counters are saved. Connecting again restores the previous session. According to the LoRaWAN + * 1.0.2 specification, the frame counters are always reset to zero for OTAA, and a new Join + * request lets the network server know that the counters need a reset. The same is said about + * the ABP, but there is no way to convey this information to the network server. For a network + * server, an ABP device is always connected. That's why storing the frame counters is important + * for ABP. That's why we restore frame counters from session information after a disconnection. + * + * @param connect Options for an end device connection to the gateway. + * + * @return Common: LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if connection parameters are invalid. + * + * For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed + * by a 'CONNECTED' event. Otherwise a negative error code is returned. + * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. + * + * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the + * first call. Any subsequent call will return either LORAWAN_STATUS_BUSY + * (if the previous request for connection is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED + * (if a network was already joined successfully). + * A 'CONNECTED' event is sent to the application when the JoinAccept is received. + */ + lorawan_status_t connect(const lorawan_connect_t &connect); + + /** Disconnect the current session. + * + * @return LORAWAN_STATUS_DEVICE_OFF on success, a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + */ + lorawan_status_t disconnect(); + + /** Validate the connectivity with the network. + * + * Application may use this API to submit a request to the stack for validation of its connectivity + * to a Network Server. Under the hood, this API schedules a Link Check Request command (LinkCheckReq) + * for the network server and once the response, i.e., LinkCheckAns MAC command is received from + * the Network Server, user provided method is called. + * + * One way to use this API may be the validation of connectivity after a long deep sleep. + * Mbed LoRaWANStack follows the MAC commands with data frame payload, so the application needs + * to send something, and the Network Server may respond during the RX slots. + * + * This API is usable only when the application sets the 'link_check_resp' callback. + * See add_lora_app_callbacks API. If the above mentioned callback is not set, + * a LORAWAN_STATUS_PARAMETER_INVALID error is thrown. + * + * The first parameter to callback function is the demodulation margin, and the second parameter + * is the number of gateways that successfully received the last request. + * + * A 'Link Check Request' MAC command remains set for every subsequent transmission, until/unless + * the application explicitly turns it off using the remove_link_check_request() API. + * + * @return LORAWAN_STATUS_OK on successfully queuing a request, or + * a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if link_check_resp callback method is not set. + * + */ + lorawan_status_t add_link_check_request(); + + /** Removes link check request sticky MAC command. + * + * Any already queued request may still be completed. However, no new requests will be made. + */ + void remove_link_check_request(); + + /** Sets up a particular data rate + * + * @param data_rate The intended data rate, for example DR_0 or DR_1. + * Please note that the macro DR_* can mean different things in different regions. + * @return LORAWAN_STATUS_OK if everything goes well, otherwise a negative error code: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if ADR is enabled or invalid data rate is given + */ + lorawan_status_t set_datarate(uint8_t data_rate); + + /** Enables adaptive data rate (ADR) + * + * The underlying LoRaPHY and LoRaMac layers handle the data rate automatically + * based on the radio conditions (network congestion). + * + * @return LORAWAN_STATUS_OK on success, negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() + */ + lorawan_status_t enable_adaptive_datarate(); + + /** Disables adaptive data rate + * + * When adaptive data rate (ADR) is disabled, either you can set a certain + * data rate, or the MAC layer selects a default value. + * + * @return LORAWAN_STATUS_OK on success, negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() + */ + lorawan_status_t disable_adaptive_datarate(); + + /** Sets up the retry counter for confirmed messages. + * + * Valid for confirmed messages only. + * + * The number of trials to transmit the frame, if the LoRaMAC layer did not receive an + * acknowledgment. The MAC performs a data rate adaptation as in the LoRaWAN Specification + * V1.0.2, chapter 18.4, table on page 64. + * + * Note that if the number of retries is set to 1 or 2, MAC does not decrease the data rate, + * if the LoRaMAC layer did not receive an acknowledgment. + * + * @param count The number of retries for confirmed messages. + * + * @return LORAWAN_STATUS_OK or a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() + * LORAWAN_STATUS_PARAMETER_INVALID if count >= 255 + */ + lorawan_status_t set_confirmed_msg_retries(uint8_t count); + + /** Sets the channel plan. + * + * You can provide a list of channels with appropriate parameters filled in. However, + * this list is not absolute. The stack applies a CF-List whenever available, which means + * that the network can overwrite your channel frequency settings right after Join Accept + * is received. You may try to set up any channel or channels after that, and if the channel + * requested is already active, the request is silently ignored. A negative error code is + * returned if there is any problem with parameters. + * + * Please note that you can also use this API to add a single channel to the existing channel plan. + * + * There is no reverse mechanism in the 1.0.2 specification for a node to request a particular + * channel. Only the network server can initiate such a request. + * You need to ensure that the corresponding base station supports the channel or channels being added. + * + * If your list includes a default channel (a channel where Join Requests are received), + * you cannot fully configure the channel parameters. Either leave the channel settings to default, + * or check your corresponding PHY layer implementation. For example, LoRaPHYE868. + * + * @param channel_plan The channel plan to set. + * + * @return LORAWAN_STATUS_OK on success, a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if number of channels is exceeding the PHY limit, + * LORAWAN_STATUS_DATARATE_INVALID if invalid data rate is given, + * LORAWAN_STATUS_FREQUENCY_INVALID if invalid frequency is given, + * LORAWAN_STATUS_FREQ_AND_DR_INVALID if invalid data rate and freqency are given, + * LORAWAN_STATUS_BUSY if TX currently ongoing, + * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY + */ + lorawan_status_t set_channel_plan(const lorawan_channelplan_t &channel_plan); + + /** Gets the channel plans from the LoRa stack. + * + * Once you have selected a particular PHY layer, a set of channels is automatically activated. + * Right after connecting, you can use this API to see the current plan. Otherwise, this API + * returns the channel plan that you have set using `set_channel_plan()`. + * + * @param channel_plan The current channel plan information. + * + * @return LORAWAN_STATUS_OK on success, a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY + */ + lorawan_status_t get_channel_plan(lorawan_channelplan_t &channel_plan); + + /** Removes an active channel plan. + * + * You cannot remove default channels (the channels the base stations are listening to). + * When a plan is abolished, only the non-default channels are removed. + * + * @return LORAWAN_STATUS_OK on success, negative error code on failure + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_BUSY if TX currently ongoing, + * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY + */ + lorawan_status_t remove_channel_plan(); + + /** Removes a single channel. + * + * You cannot remove default channels (the channels the base stations are listening to). + * + * @param index The channel index. + * + * @return LORAWAN_STATUS_OK on success, negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if invalid channel index is given, + * LORAWAN_STATUS_BUSY if TX currently ongoing, + * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY + */ + lorawan_status_t remove_channel(uint8_t index); + + /** Send message to gateway + * + * @param port The application port number. Port numbers 0 and 224 are reserved, + * whereas port numbers from 1 to 223 (0x01 to 0xDF) are valid port numbers. + * Anything out of this range is illegal. + * + * @param data A pointer to the data being sent. The ownership of the buffer is not transferred. + * The data is copied to the internal buffers. + * + * @param length The size of data in bytes. + * + * @param flags A flag used to determine what type of message is being sent, for example: + * + * MSG_UNCONFIRMED_FLAG = 0x01 + * MSG_CONFIRMED_FLAG = 0x02 + * MSG_MULTICAST_FLAG = 0x04 + * MSG_PROPRIETARY_FLAG = 0x08 + * + * All flags are mutually exclusive, and MSG_MULTICAST_FLAG cannot be set. + * + * @return The number of bytes sent, or a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, + * LORAWAN_STATUS_WOULD_BLOCK if another TX is ongoing, + * LORAWAN_STATUS_PORT_INVALID if trying to send to an invalid port (e.g. to 0) + * LORAWAN_STATUS_PARAMETER_INVALID if NULL data pointer is given or flags are invalid. + */ + int16_t send(uint8_t port, const uint8_t *data, uint16_t length, int flags); + + /** Receives a message from the Network Server on a specific port. + * + * @param port The application port number. Port numbers 0 and 224 are reserved, + * whereas port numbers from 1 to 223 (0x01 to 0xDF) are valid port numbers. + * Anything out of this range is illegal. + * + * @param data A pointer to buffer where the received data will be stored. + * + * @param length The size of data in bytes. + * + * @param flags A flag is used to determine what type of message is being sent, for example: + * + * MSG_UNCONFIRMED_FLAG = 0x01 + * MSG_CONFIRMED_FLAG = 0x02 + * MSG_MULTICAST_FLAG = 0x04 + * MSG_PROPRIETARY_FLAG = 0x08 + * + * All flags can be used in conjunction with one another depending on the intended + * use case or reception expectation. + * + * For example, MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are + * not mutually exclusive. In other words, the user can subscribe to + * receive both CONFIRMED AND UNCONFIRMED messages at the same time. + * + * @return It could be one of these: + * i) 0 if there is nothing else to read. + * ii) Number of bytes written to user buffer. + * iii) A negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, + * LORAWAN_STATUS_WOULD_BLOCK if there is nothing available to read at the moment, + * LORAWAN_STATUS_PARAMETER_INVALID if NULL data or length is given, + * LORAWAN_STATUS_WOULD_BLOCK if incorrect port or flags are given, + */ + int16_t receive(uint8_t port, uint8_t *data, uint16_t length, int flags); + + /** Receives a message from the Network Server on any port. + * + * @param data A pointer to buffer where the received data will be stored. + * + * @param length The size of data in bytes + * + * @param port Return the number of port from which message was received. + * + * @param flags Return flags to determine what type of message was received. + * MSG_UNCONFIRMED_FLAG = 0x01 + * MSG_CONFIRMED_FLAG = 0x02 + * MSG_MULTICAST_FLAG = 0x04 + * MSG_PROPRIETARY_FLAG = 0x08 + * + * @return It could be one of these: + * i) 0 if there is nothing else to read. + * ii) Number of bytes written to user buffer. + * iii) A negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, + * LORAWAN_STATUS_PARAMETER_INVALID if NULL data or length is given, + * LORAWAN_STATUS_WOULD_BLOCK if there is nothing available to read at the moment. + */ + int16_t receive(uint8_t *data, uint16_t length, uint8_t &port, int &flags); + + /** Add application callbacks to the stack. + * + * An example of using this API with a latch onto 'lorawan_events' could be: + * + *\code + * LoRaWANInterface lorawan(radio); + * lorawan_app_callbacks_t cbs; + * static void my_event_handler(); + * + * int main() + * { + * lorawan.initialize(); + * cbs.lorawan_events = mbed::callback(my_event_handler); + * lorawan.add_app_callbacks(&cbs); + * lorawan.connect(); + * } + * + * static void my_event_handler(lorawan_event_t event) + * { + * switch(event) { + * case CONNECTED: + * //do something + * break; + * case DISCONNECTED: + * //do something + * break; + * case TX_DONE: + * //do something + * break; + * default: + * break; + * } + * } + * + *\endcode + * + * @param callbacks A pointer to the structure containing application callbacks. + * + * @return LORAWAN_STATUS_OK on success, a negative error code on failure: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_PARAMETER_INVALID if events callback is not set + */ + lorawan_status_t add_app_callbacks(lorawan_app_callbacks_t *callbacks); + + /** Change device class + * + * Change current device class. + * + * @param device_class The device class + * + * @return LORAWAN_STATUS_OK on success or other negative error code if request failed: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_UNSUPPORTED if requested class is not supported + */ + lorawan_status_t set_device_class(device_class_t device_class); + + /** Get hold of TX meta-data + * + * Use this method to acquire any TX meta-data related to previous transmission. + * TX meta-data is only available right after the transmission is completed. + * In other words, you can check for TX meta-data right after receiving the TX_DONE event. + * + * @param metadata the inbound structure that will be filled if the meta-data is available. + * + * @return LORAWAN_STATUS_OK if the meta-data is available, + * otherwise other negative error code if request failed: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available + */ + lorawan_status_t get_tx_metadata(lorawan_tx_metadata &metadata); + + /** Get hold of RX meta-data + * + * Use this method to acquire any RX meta-data related to current reception. + * RX meta-data is only available right after the reception is completed. + * In other words, you can check for RX meta-data right after receiving the RX_DONE event. + * + * @param metadata the inbound structure that will be filled if the meta-data is available. + * + * @return LORAWAN_STATUS_OK if the meta-data is available, + * otherwise other negative error code if request failed: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available + */ + lorawan_status_t get_rx_metadata(lorawan_rx_metadata &metadata); + + /** Get hold of backoff time + * + * In the TX path, because of automatic duty cycling, the transmission is delayed by a certain + * amount of time, which is the backoff time. While the system schedules application data to be sent, + * the application can inquire about how much time is left in the actual transmission to happen. + * + * The system will provide you with a backoff time only if the application data is in the TX pipe. + * If however, the event is already queued for the transmission, this API returns a + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE error code. + * + * @param backoff the inbound integer that will carry the backoff time if it is available. + * + * @return LORAWAN_STATUS_OK if the meta-data is available, + * otherwise other negative error code if request failed: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available + */ + lorawan_status_t get_backoff_metadata(int &backoff); + + /** Cancel outgoing transmission + * + * This API is used to cancel any outstanding transmission in the TX pipe. + * If an event for transmission is not already queued at the end of backoff timer, + * the system can cancel the outstanding outgoing packet. Otherwise, the system is + * busy sending and can't be held back. The system will not try to resend if the + * outgoing message was a CONFIRMED message even if the ack is not received. + * + * @return LORAWAN_STATUS_OK if the sending is canceled, otherwise + * other negative error code if request failed: + * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), + * LORAWAN_STATUS_BUSY if the send cannot be canceled + * LORAWAN_STATUS_NO_OP if the operation cannot be completed (nothing to cancel) + */ + lorawan_status_t cancel_sending(void); + + /** Provides exclusive access to the stack. + * + * Use only if the stack is being run in it's own separate thread. + */ + void lock(void) + { + _lw_stack.lock(); + } + + /** Releases exclusive access to the stack. + * + * Use only if the stack is being run in it's own separate thread. + */ + void unlock(void) + { + _lw_stack.unlock(); + } + +private: + /** ScopedLock object + * + * RAII style exclusive access + */ + typedef mbed::ScopedLock Lock; + + /** LoRaWANStack object + * + * Handle for the LoRaWANStack class + */ + LoRaWANStack _lw_stack; + + /** PHY object if created by LoRaWANInterface + * + * PHY object if LoRaWANInterface has created it. + * If PHY object is provided by the application, this pointer is NULL. + */ + LoRaPHY *_default_phy; +}; + +#endif /* LORAWANINTERFACE_H_ */ +/** @}*/ diff --git a/connectivity/lorawan/LoRaWANStack.cpp b/connectivity/lorawan/LoRaWANStack.cpp new file mode 100644 index 0000000..d60fa0b --- /dev/null +++ b/connectivity/lorawan/LoRaWANStack.cpp @@ -0,0 +1,1266 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRaWAN stack layer that controls both MAC and PHY underneath + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include +#include +#include "platform/Callback.h" +#include "events/EventQueue.h" + +#include "LoRaWANStack.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "LSTK" + +#define INVALID_PORT 0xFF +#define MAX_CONFIRMED_MSG_RETRIES 255 +#define COMPLIANCE_TESTING_PORT 224 +/** + * Control flags for transient states + */ +#define IDLE_FLAG 0x00000000 +#define RETRY_EXHAUSTED_FLAG 0x00000001 +#define MSG_RECVD_FLAG 0x00000002 +#define CONNECTED_FLAG 0x00000004 +#define USING_OTAA_FLAG 0x00000008 +#define TX_DONE_FLAG 0x00000010 +#define CONN_IN_PROGRESS_FLAG 0x00000020 + +using namespace mbed; +using namespace events; + +/** + * Bit mask for message flags + */ + +#define MSG_FLAG_MASK 0x0F + +/***************************************************************************** + * Constructor * + ****************************************************************************/ +LoRaWANStack::LoRaWANStack() + : _loramac(), + _device_current_state(DEVICE_STATE_NOT_INITIALIZED), + _lw_session(), + _tx_msg(), + _rx_msg(), + _tx_metadata(), + _rx_metadata(), + _num_retry(1), + _qos_cnt(1), + _ctrl_flags(IDLE_FLAG), + _app_port(INVALID_PORT), + _link_check_requested(false), + _automatic_uplink_ongoing(false), + _queue(NULL) +{ + _tx_metadata.stale = true; + _rx_metadata.stale = true; + core_util_atomic_flag_clear(&_rx_payload_in_use); + +#ifdef MBED_CONF_LORA_APP_PORT + if (is_port_valid(MBED_CONF_LORA_APP_PORT)) { + _app_port = MBED_CONF_LORA_APP_PORT; + } else { + tr_error("User defined port in .json is illegal."); + } +#endif +} + +/***************************************************************************** + * Public Methods * + ****************************************************************************/ +void LoRaWANStack::bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy) +{ + radio_events.tx_done = mbed::callback(this, &LoRaWANStack::tx_interrupt_handler); + radio_events.rx_done = mbed::callback(this, &LoRaWANStack::rx_interrupt_handler); + radio_events.rx_error = mbed::callback(this, &LoRaWANStack::rx_error_interrupt_handler); + radio_events.tx_timeout = mbed::callback(this, &LoRaWANStack::tx_timeout_interrupt_handler); + radio_events.rx_timeout = mbed::callback(this, &LoRaWANStack::rx_timeout_interrupt_handler); + + phy.set_radio_instance(radio); + _loramac.bind_phy(phy); + + radio.lock(); + radio.init_radio(&radio_events); + radio.unlock(); +} + +lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) +{ + if (!queue) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + tr_debug("Initializing MAC layer"); + _queue = queue; + + return state_controller(DEVICE_STATE_IDLE); +} + +lorawan_status_t LoRaWANStack::set_lora_callbacks(const lorawan_app_callbacks_t *callbacks) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!callbacks || !callbacks->events) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + _callbacks.events = callbacks->events; + + if (callbacks->link_check_resp) { + _callbacks.link_check_resp = callbacks->link_check_resp; + } + + if (callbacks->battery_level) { + _callbacks.battery_level = callbacks->battery_level; + _loramac.set_batterylevel_callback(callbacks->battery_level); + } + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaWANStack::connect() +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { + return LORAWAN_STATUS_BUSY; + } + + if (_ctrl_flags & CONNECTED_FLAG) { + return LORAWAN_STATUS_ALREADY_CONNECTED; + } + + lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); + + if (LORAWAN_STATUS_OK != status) { + return status; + } + + return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); +} + +lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { + return LORAWAN_STATUS_BUSY; + } + + if (_ctrl_flags & CONNECTED_FLAG) { + return LORAWAN_STATUS_ALREADY_CONNECTED; + } + + if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA) + && !(connect.connect_type == LORAWAN_CONNECTION_ABP)) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA); + + lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa); + + if (LORAWAN_STATUS_OK != status) { + return status; + } + + return handle_connect(is_otaa); +} + +lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return _loramac.add_channel_plan(channel_plan); +} + +lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return _loramac.remove_single_channel(channel_id); +} + +lorawan_status_t LoRaWANStack::drop_channel_list() +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return _loramac.remove_channel_plan(); +} + +lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t &channel_plan) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return _loramac.get_channel_plan(channel_plan); +} + +lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (count >= MAX_CONFIRMED_MSG_RETRIES) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + _num_retry = count; + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return _loramac.set_channel_data_rate(data_rate); +} + + +lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + _loramac.enable_adaptive_datarate(adr_enabled); + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaWANStack::stop_sending(void) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + lorawan_status_t status = _loramac.clear_tx_pipe(); + + if (status == LORAWAN_STATUS_OK) { + _ctrl_flags &= ~TX_DONE_FLAG; + _loramac.set_tx_ongoing(false); + _device_current_state = DEVICE_STATE_IDLE; + return LORAWAN_STATUS_OK; + } + + return status; +} + +int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data, + uint16_t length, uint8_t flags, + bool null_allowed, bool allow_port_0) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!null_allowed && !data) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + if (!_lw_session.active) { + return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; + } + + if (_loramac.tx_ongoing()) { + return LORAWAN_STATUS_WOULD_BLOCK; + } + + // add a link check request with normal data, until the application + // explicitly removes it. + if (_link_check_requested) { + _loramac.setup_link_check_request(); + } + _qos_cnt = 1; + + lorawan_status_t status; + + if (_loramac.nwk_joined() == false) { + return LORAWAN_STATUS_NO_NETWORK_JOINED; + } + + status = set_application_port(port, allow_port_0); + + if (status != LORAWAN_STATUS_OK) { + tr_error("Illegal application port definition."); + return status; + } + + // All the flags are mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be + // used for uplink. + switch (flags & MSG_FLAG_MASK) { + case MSG_UNCONFIRMED_FLAG: + case MSG_CONFIRMED_FLAG: + case MSG_PROPRIETARY_FLAG: + break; + + default: + tr_error("Invalid send flags"); + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry); + + status = state_controller(DEVICE_STATE_SCHEDULING); + + // send user the length of data which is scheduled now. + // user should take care of the pending data. + return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status; +} + +int16_t LoRaWANStack::handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!_lw_session.active) { + return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; + } + + // No messages to read. + if (!_rx_msg.receive_ready) { + return LORAWAN_STATUS_WOULD_BLOCK; + } + + if (data == NULL || length == 0) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type); + if (validate_params) { + // Check received message port and flags match with the ones requested by user + received_flags &= MSG_FLAG_MASK; + + if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) { + return LORAWAN_STATUS_WOULD_BLOCK; + } + } + + // Report values back to user + port = _rx_msg.msg.mcps_indication.port; + flags = received_flags; + + const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer; + uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size; + bool read_complete = false; + + if (_rx_msg.pending_size == 0) { + _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size; + _rx_msg.prev_read_size = 0; + } + + // check the length of received message whether we can fit into user + // buffer completely or not + if (_rx_msg.prev_read_size == 0 && _rx_msg.msg.mcps_indication.buffer_size <= length) { + memcpy(data, base_ptr, base_size); + read_complete = true; + } else if (_rx_msg.pending_size > length) { + _rx_msg.pending_size = _rx_msg.pending_size - length; + base_size = length; + memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); + _rx_msg.prev_read_size += base_size; + } else { + base_size = _rx_msg.pending_size; + memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); + read_complete = true; + } + + if (read_complete) { + _rx_msg.msg.mcps_indication.buffer = NULL; + _rx_msg.msg.mcps_indication.buffer_size = 0; + _rx_msg.pending_size = 0; + _rx_msg.receive_ready = false; + } + + return base_size; +} + +lorawan_status_t LoRaWANStack::set_link_check_request() +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!_callbacks.link_check_resp) { + tr_error("Must assign a callback function for link check request. "); + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + _link_check_requested = true; + return LORAWAN_STATUS_OK; +} + +void LoRaWANStack::remove_link_check_request() +{ + _link_check_requested = false; +} + +lorawan_status_t LoRaWANStack::shutdown() +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + return state_controller(DEVICE_STATE_SHUTDOWN); +} + +lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_class) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (device_class == CLASS_B) { + return LORAWAN_STATUS_UNSUPPORTED; + } + _loramac.set_device_class(device_class, + mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception)); + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaWANStack::acquire_tx_metadata(lorawan_tx_metadata &tx_metadata) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!_tx_metadata.stale) { + tx_metadata = _tx_metadata; + _tx_metadata.stale = true; + return LORAWAN_STATUS_OK; + } + + return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; +} + +lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + if (!_rx_metadata.stale) { + metadata = _rx_metadata; + _rx_metadata.stale = true; + return LORAWAN_STATUS_OK; + } + + return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; +} + +lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff) +{ + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + return LORAWAN_STATUS_NOT_INITIALIZED; + } + + int id = _loramac.get_backoff_timer_event_id(); + + if (_loramac.get_backoff_timer_event_id() > 0) { + backoff = _queue->time_left(id); + return LORAWAN_STATUS_OK; + } + + backoff = -1; + return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; +} + +/***************************************************************************** + * Interrupt handlers * + ****************************************************************************/ +void LoRaWANStack::tx_interrupt_handler(void) +{ + _tx_timestamp = _loramac.get_current_time(); + const int ret = _queue->call(this, &LoRaWANStack::process_transmission); + MBED_ASSERT(ret != 0); + (void)ret; +} + +void LoRaWANStack::rx_interrupt_handler(const uint8_t *payload, uint16_t size, + int16_t rssi, int8_t snr) +{ + if (size > sizeof _rx_payload || core_util_atomic_flag_test_and_set(&_rx_payload_in_use)) { + return; + } + + memcpy(_rx_payload, payload, size); + + const uint8_t *ptr = _rx_payload; + const int ret = _queue->call(this, &LoRaWANStack::process_reception, + ptr, size, rssi, snr); + MBED_ASSERT(ret != 0); + (void)ret; +} + +void LoRaWANStack::rx_error_interrupt_handler(void) +{ + const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, + false); + MBED_ASSERT(ret != 0); + (void)ret; +} + +void LoRaWANStack::tx_timeout_interrupt_handler(void) +{ + const int ret = _queue->call(this, &LoRaWANStack::process_transmission_timeout); + MBED_ASSERT(ret != 0); + (void)ret; +} + +void LoRaWANStack::rx_timeout_interrupt_handler(void) +{ + const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, + true); + MBED_ASSERT(ret != 0); + (void)ret; +} + +/***************************************************************************** + * Processors for deferred interrupts * + ****************************************************************************/ +void LoRaWANStack::process_transmission_timeout() +{ + // this is a fatal error and should not happen + tr_debug("TX Timeout"); + _loramac.on_radio_tx_timeout(); + _ctrl_flags &= ~TX_DONE_FLAG; + if (_device_current_state == DEVICE_STATE_JOINING) { + mlme_confirm_handler(); + } else { + state_controller(DEVICE_STATE_STATUS_CHECK); + } + + state_machine_run_to_completion(); +} + +void LoRaWANStack::process_transmission(void) +{ + tr_debug("Transmission completed"); + + if (_device_current_state == DEVICE_STATE_JOINING) { + _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; + } + + if (_device_current_state == DEVICE_STATE_SENDING) { + if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { + tr_debug("Awaiting ACK"); + _device_current_state = DEVICE_STATE_AWAITING_ACK; + } + } + + _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 &= ~RETRY_EXHAUSTED_FLAG; + tr_debug("Ack=OK, NbTrials=%d", + _loramac.get_mcps_confirmation()->nb_retries); + _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; + _loramac.post_process_mcps_req(); + make_tx_metadata_available(); + 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); + } + } +} + +void LoRaWANStack::post_process_tx_no_reception() +{ + if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { + if (_loramac.continue_sending_process()) { + _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_machine_run_to_completion(); +} + +void LoRaWANStack::handle_scheduling_failure(void) +{ + tr_error("Failed to schedule transmission"); + state_controller(DEVICE_STATE_STATUS_CHECK); + state_machine_run_to_completion(); +} + + +void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size, + int16_t rssi, int8_t snr) +{ + _device_current_state = DEVICE_STATE_RECEIVING; + + _ctrl_flags &= ~MSG_RECVD_FLAG; + _ctrl_flags &= ~TX_DONE_FLAG; + _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; + + _loramac.on_radio_rx_done(payload, size, rssi, snr); + + if (_loramac.get_mlme_confirmation()->pending) { + _loramac.post_process_mlme_request(); + mlme_confirm_handler(); + + if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { + core_util_atomic_flag_clear(&_rx_payload_in_use); + return; + } + } + + if (!_loramac.nwk_joined()) { + core_util_atomic_flag_clear(&_rx_payload_in_use); + return; + } + + make_rx_metadata_available(); + + // Post process transmission in response to the reception + post_process_tx_with_reception(); + + // handle any pending MCPS indication + if (_loramac.get_mcps_indication()->pending) { + _loramac.post_process_mcps_ind(); + _ctrl_flags |= MSG_RECVD_FLAG; + state_controller(DEVICE_STATE_STATUS_CHECK); + } + + // complete the cycle only if TX_DONE_FLAG is set + if (_ctrl_flags & TX_DONE_FLAG) { + state_machine_run_to_completion(); + } + + // 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"); + _loramac.post_process_mlme_ind(); + tr_debug("Immediate Uplink requested"); + mlme_indication_handler(); + } + + core_util_atomic_flag_clear(&_rx_payload_in_use); +} + +void LoRaWANStack::process_reception_timeout(bool is_timeout) +{ + rx_slot_t slot = _loramac.get_current_slot(); + + // when is_timeout == false, a CRC error took place in the received frame + // we treat that erroneous frame as no frame received at all, hence handle + // it exactly as we would handle timeout + _loramac.on_radio_rx_timeout(is_timeout); + + if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) { + state_controller(DEVICE_STATE_JOINING); + return; + } + + /** + * LoRaWAN Specification 1.0.2. Section 3.3.6 + * Main point: + * We indicate successful transmission + * of UNCONFIRMED message after RX windows are done with. + * For a CONFIRMED message, it means that we have not received + * ack (actually nothing was received), and we should retransmit if we can. + * + * NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout + * never occurs. + */ + if (slot == RX_SLOT_WIN_2) { + post_process_tx_no_reception(); + } +} + +/***************************************************************************** + * Private methods * + ****************************************************************************/ +void LoRaWANStack::make_tx_metadata_available(void) +{ + _tx_metadata.stale = false; + _tx_metadata.channel = _loramac.get_mcps_confirmation()->channel; + _tx_metadata.data_rate = _loramac.get_mcps_confirmation()->data_rate; + _tx_metadata.tx_power = _loramac.get_mcps_confirmation()->tx_power; + _tx_metadata.tx_toa = _loramac.get_mcps_confirmation()->tx_toa; + _tx_metadata.nb_retries = _loramac.get_mcps_confirmation()->nb_retries; +} + +void LoRaWANStack::make_rx_metadata_available(void) +{ + _rx_metadata.stale = false; + _rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate; + _rx_metadata.rssi = _loramac.get_mcps_indication()->rssi; + _rx_metadata.snr = _loramac.get_mcps_indication()->snr; + _rx_metadata.channel = _loramac.get_mcps_indication()->channel; + _rx_metadata.rx_toa = _loramac.get_mcps_indication()->rx_toa; +} + +bool LoRaWANStack::is_port_valid(const uint8_t port, bool allow_port_0) +{ + //Application should not use reserved and illegal port numbers. + if (port == 0) { + return allow_port_0; + } else if (port == COMPLIANCE_TESTING_PORT) { +#if !defined(LORAWAN_COMPLIANCE_TEST) + return false; +#endif + } else { + return true; + } + + // fallback for compliance testing port if LORAWAN_COMPLIANCE_TEST + // was defined + return true; +} + +lorawan_status_t LoRaWANStack::set_application_port(const uint8_t port, bool allow_port_0) +{ + if (is_port_valid(port, allow_port_0)) { + _app_port = port; + return LORAWAN_STATUS_OK; + } + + return LORAWAN_STATUS_PORT_INVALID; +} + +void LoRaWANStack::state_machine_run_to_completion() +{ + if (_loramac.get_device_class() == CLASS_C) { + _device_current_state = DEVICE_STATE_RECEIVING; + return; + } + + _device_current_state = DEVICE_STATE_IDLE; +} + +void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const +{ + if (_callbacks.events) { + const int ret = _queue->call(_callbacks.events, event); + MBED_ASSERT(ret != 0); + (void)ret; + } +} + +void LoRaWANStack::send_automatic_uplink_message(const uint8_t port) +{ + // we will silently ignore the automatic uplink event if the user is already + // sending something + const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true); + if (ret == LORAWAN_STATUS_WOULD_BLOCK) { + _automatic_uplink_ongoing = false; + } else if (ret < 0) { + tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret); + send_event_to_application(AUTOMATIC_UPLINK_ERROR); + } +} + +int LoRaWANStack::convert_to_msg_flag(const mcps_type_t type) +{ + int msg_flag = MSG_UNCONFIRMED_FLAG; + switch (type) { + case MCPS_UNCONFIRMED: + msg_flag = MSG_UNCONFIRMED_FLAG; + break; + + case MCPS_CONFIRMED: + msg_flag = MSG_CONFIRMED_FLAG; + break; + + case MCPS_MULTICAST: + msg_flag = MSG_MULTICAST_FLAG; + break; + + case MCPS_PROPRIETARY: + msg_flag = MSG_PROPRIETARY_FLAG; + break; + + default: + tr_error("Unknown message type!"); + MBED_ASSERT(0); + } + + return msg_flag; +} + +lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa) +{ + _ctrl_flags |= CONN_IN_PROGRESS_FLAG; + + if (is_otaa) { + tr_debug("Initiating OTAA"); + + // In 1.0.2 spec, counters are always set to zero for new connection. + // This section is common for both normal and + // connection restore at this moment. Will change in future with 1.1 support. + _lw_session.downlink_counter = 0; + _lw_session.uplink_counter = 0; + _ctrl_flags |= USING_OTAA_FLAG; + } else { + // If current state is SHUTDOWN, device may be trying to re-establish + // communication. In case of ABP specification is meddled about frame counters. + // It says to reset counters to zero but there is no mechanism to tell the + // network server that the device was disconnected or restarted. + // At the moment, this implementation does not support a non-volatile + // memory storage. + //_lw_session.downlink_counter; //Get from NVM + //_lw_session.uplink_counter; //Get from NVM + + tr_debug("Initiating ABP"); + tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", + _lw_session.uplink_counter, _lw_session.downlink_counter); + _ctrl_flags &= ~USING_OTAA_FLAG; + } + + return state_controller(DEVICE_STATE_CONNECTING); +} + +void LoRaWANStack::mlme_indication_handler() +{ + if (_loramac.get_mlme_indication()->indication_type == MLME_SCHEDULE_UPLINK) { + // The MAC signals that we shall provide an uplink as soon as possible +#if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE + _automatic_uplink_ongoing = true; + tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands..."); + const uint8_t port = 0; + const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port); + MBED_ASSERT(ret != 0); + (void)ret; +#else + send_event_to_application(UPLINK_REQUIRED); +#endif + return; + } + + tr_error("Unknown MLME Indication type."); +} + +void LoRaWANStack::mlme_confirm_handler() +{ + if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK) { + if (_loramac.get_mlme_confirmation()->status + == LORAMAC_EVENT_INFO_STATUS_OK) { + + if (_callbacks.link_check_resp) { + const int ret = _queue->call( + _callbacks.link_check_resp, + _loramac.get_mlme_confirmation()->demod_margin, + _loramac.get_mlme_confirmation()->nb_gateways); + MBED_ASSERT(ret != 0); + (void) ret; + } + } + } + + if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { + + switch (_loramac.get_mlme_confirmation()->status) { + case LORAMAC_EVENT_INFO_STATUS_OK: + state_controller(DEVICE_STATE_CONNECTED); + break; + + case LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL: + // fatal error + _device_current_state = DEVICE_STATE_IDLE; + tr_error("Joining abandoned: CRYPTO_ERROR"); + send_event_to_application(CRYPTO_ERROR); + break; + + case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: + // fatal error + _device_current_state = DEVICE_STATE_IDLE; + tr_error("Joining abandoned: Radio failed to transmit"); + send_event_to_application(TX_TIMEOUT); + break; + + default: + // non-fatal, retry if possible + _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; + state_controller(DEVICE_STATE_JOINING); + } + } +} + +void LoRaWANStack::mcps_confirm_handler() +{ + switch (_loramac.get_mcps_confirmation()->status) { + + case LORAMAC_EVENT_INFO_STATUS_OK: + _lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter; + send_event_to_application(TX_DONE); + break; + + case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: + tr_error("Fatal Error, Radio failed to transmit"); + send_event_to_application(TX_TIMEOUT); + break; + + case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: + send_event_to_application(TX_SCHEDULING_ERROR); + break; + + default: + // if no ack was received after enough retries, send TX_ERROR + send_event_to_application(TX_ERROR); + } +} + +void LoRaWANStack::mcps_indication_handler() +{ + const loramac_mcps_indication_t *mcps_indication = _loramac.get_mcps_indication(); + if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) { + tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status); + send_event_to_application(RX_ERROR); + return; + } + + _lw_session.downlink_counter = mcps_indication->dl_frame_counter; + + /** + * Check port, if it's compliance testing port and the compliance testing is + * not enabled, give up silently + */ + if (mcps_indication->port == COMPLIANCE_TESTING_PORT) { +#if !defined(LORAWAN_COMPLIANCE_TEST) + return; +#endif + } + + if (mcps_indication->is_data_recvd) { + // Valid message arrived. + _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; + _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size; + _rx_msg.msg.mcps_indication.port = mcps_indication->port; + _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer; + _rx_msg.msg.mcps_indication.type = mcps_indication->type; + + // Notify application about received frame.. + tr_debug("Packet Received %d bytes, Port=%d", + _rx_msg.msg.mcps_indication.buffer_size, + mcps_indication->port); + _rx_msg.receive_ready = true; + send_event_to_application(RX_DONE); + } + + /* + * If fPending bit is set we try to generate an empty packet + * with CONFIRMED flag set. We always set a CONFIRMED flag so + * that we could retry a certain number of times if the uplink + * failed for some reason + * or + * Class C and node received a confirmed message so we need to + * send an empty packet to acknowledge the message. + * This scenario is unspecified by LoRaWAN 1.0.2 specification, + * but version 1.1.0 says that network SHALL not send any new + * confirmed messages until ack has been sent + */ + if ((_loramac.get_device_class() != CLASS_C + && mcps_indication->fpending_status) + || (_loramac.get_device_class() == CLASS_C + && mcps_indication->type == MCPS_CONFIRMED)) { +#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE) + // Do not queue an automatic uplink of there is one already outgoing + // This means we have not received an ack for the previous automatic uplink + if (!_automatic_uplink_ongoing) { + tr_debug("Sending empty uplink message..."); + _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 + send_event_to_application(UPLINK_REQUIRED); +#endif + } +} + + +lorawan_status_t LoRaWANStack::state_controller(device_states_t new_state) +{ + lorawan_status_t status = LORAWAN_STATUS_OK; + + switch (new_state) { + case DEVICE_STATE_IDLE: + process_idle_state(status); + break; + case DEVICE_STATE_CONNECTING: + process_connecting_state(status); + break; + case DEVICE_STATE_JOINING: + process_joining_state(status); + break; + case DEVICE_STATE_CONNECTED: + process_connected_state(); + break; + case DEVICE_STATE_SCHEDULING: + process_scheduling_state(status); + break; + case DEVICE_STATE_STATUS_CHECK: + process_status_check_state(); + break; + case DEVICE_STATE_SHUTDOWN: + process_shutdown_state(status); + break; + default: + //Because this is internal function only coding error causes this + tr_error("Unknown state: %d:", new_state); + MBED_ASSERT(false); + } + + return status; +} + +void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status) +{ + /** + * Remove channels + * Radio will be put to sleep by the APIs underneath + */ + drop_channel_list(); + _loramac.disconnect(); + _lw_session.active = false; + _device_current_state = DEVICE_STATE_SHUTDOWN; + op_status = LORAWAN_STATUS_DEVICE_OFF; + _ctrl_flags = 0; + send_event_to_application(DISCONNECTED); +} + +void LoRaWANStack::process_status_check_state() +{ + if (_device_current_state == DEVICE_STATE_SENDING || + _device_current_state == DEVICE_STATE_AWAITING_ACK) { + // If there was a successful transmission, this block gets a kick after + // RX2 slot is exhausted. We may or may not have a successful UNCONFIRMED transmission + // here. In CONFIRMED case this block is invoked only + // when the MAX number of retries are exhausted, i.e., only error + // case will fall here. Moreover, it will happen for Class A only. + // Another possibility is the case when the stack fails to schedule a + // deferred transmission and a scheduling failure handler is invoked. + _ctrl_flags &= ~TX_DONE_FLAG; + _loramac.set_tx_ongoing(false); + _loramac.reset_ongoing_tx(); + mcps_confirm_handler(); + + } else if (_device_current_state == DEVICE_STATE_RECEIVING) { + + if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) { + _ctrl_flags &= ~TX_DONE_FLAG; + _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; + _loramac.set_tx_ongoing(false); + _loramac.reset_ongoing_tx(); + // if an automatic uplink is ongoing, we should not send a TX_DONE + // event to application + if (_automatic_uplink_ongoing) { + _automatic_uplink_ongoing = false; + } else { + mcps_confirm_handler(); + } + } + + // handle any received data and send event accordingly + if (_ctrl_flags & MSG_RECVD_FLAG) { + _ctrl_flags &= ~MSG_RECVD_FLAG; + mcps_indication_handler(); + } + } +} + +void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status) +{ + if (_device_current_state != DEVICE_STATE_IDLE) { + if (_device_current_state != DEVICE_STATE_RECEIVING + && _loramac.get_device_class() != CLASS_C) { + op_status = LORAWAN_STATUS_BUSY; + return; + } + } + + op_status = _loramac.send_ongoing_tx(); + if (op_status == LORAWAN_STATUS_OK) { + _ctrl_flags &= ~TX_DONE_FLAG; + _loramac.set_tx_ongoing(true); + _device_current_state = DEVICE_STATE_SENDING; + } +} + +void LoRaWANStack::process_joining_state(lorawan_status_t &op_status) +{ + if (_device_current_state == DEVICE_STATE_CONNECTING) { + _device_current_state = DEVICE_STATE_JOINING; + tr_debug("Sending Join Request ..."); + op_status = _loramac.join(true); + return; + } + + if (_device_current_state == DEVICE_STATE_AWAITING_JOIN_ACCEPT && + _loramac.get_current_slot() != RX_SLOT_WIN_1) { + _device_current_state = DEVICE_STATE_JOINING; + // retry join + bool can_continue = _loramac.continue_joining_process(); + + if (!can_continue) { + _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; + send_event_to_application(JOIN_FAILURE); + _device_current_state = DEVICE_STATE_IDLE; + return; + } + } +} + +void LoRaWANStack::process_connected_state() +{ + _ctrl_flags |= CONNECTED_FLAG; + _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; + + if (_ctrl_flags & USING_OTAA_FLAG) { + tr_debug("OTAA Connection OK!"); + } + + _lw_session.active = true; + send_event_to_application(CONNECTED); + + _device_current_state = DEVICE_STATE_IDLE; +} + +void LoRaWANStack::process_connecting_state(lorawan_status_t &op_status) +{ + MBED_ASSERT(_device_current_state == DEVICE_STATE_IDLE || + _device_current_state == DEVICE_STATE_SHUTDOWN); + + _device_current_state = DEVICE_STATE_CONNECTING; + + if (_ctrl_flags & USING_OTAA_FLAG) { + process_joining_state(op_status); + return; + } + + op_status = _loramac.join(false); + tr_debug("ABP connection OK."); + process_connected_state(); +} + +void LoRaWANStack::process_idle_state(lorawan_status_t &op_status) +{ + if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { + _device_current_state = DEVICE_STATE_IDLE; + process_uninitialized_state(op_status); + return; + } + + _device_current_state = DEVICE_STATE_IDLE; + op_status = LORAWAN_STATUS_OK; +} + +void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status) +{ + op_status = _loramac.initialize(_queue, mbed::callback(this, + &LoRaWANStack::handle_scheduling_failure)); + + if (op_status == LORAWAN_STATUS_OK) { + _device_current_state = DEVICE_STATE_IDLE; + } +} diff --git a/connectivity/lorawan/LoRaWANStack.h b/connectivity/lorawan/LoRaWANStack.h new file mode 100644 index 0000000..dbdcac0 --- /dev/null +++ b/connectivity/lorawan/LoRaWANStack.h @@ -0,0 +1,517 @@ +/** + * \file LoRaWANStack.h + * + * \brief LoRaWAN stack layer implementation + * + * \copyright Revised BSD License, see LICENSE.TXT file include in the project + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) + * + * \defgroup LoRaWAN stack layer that controls MAC layer underneath + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Copyright (c) 2017, Arm Limited and affiliates. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef LORAWANSTACK_H_ +#define LORAWANSTACK_H_ + +#include +#include "events/EventQueue.h" +#include "platform/mbed_atomic.h" +#include "platform/Callback.h" +#include "platform/NonCopyable.h" +#include "platform/ScopedLock.h" + +#include "lorastack/mac/LoRaMac.h" +#include "system/LoRaWANTimer.h" +#include "system/lorawan_data_structures.h" +#include "LoRaRadio.h" + +class LoRaPHY; + +/** LoRaWANStack Class + * A controller layer for LoRaWAN MAC and PHY + */ +class LoRaWANStack: private mbed::NonCopyable { + +public: + LoRaWANStack(); + + /** Binds PHY layer and radio driver to stack. + * + * MAC layer is totally detached from the PHY layer so the stack layer + * needs to play the role of an arbitrator. + * This API sets the PHY layer object to stack and bind the radio driver + * object from the application to the PHY layer. + * Also initialises radio callback handles which the radio driver will + * use in order to report events. + * + * @param radio LoRaRadio object, i.e., the radio driver + * @param phy LoRaPHY object. + * + */ + void bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy); + + /** End device initialization. + * @param queue A pointer to an EventQueue passed from the application. + * @return LORAWAN_STATUS_OK on success, a negative error code on failure. + */ + lorawan_status_t initialize_mac_layer(events::EventQueue *queue); + + /** Sets all callbacks for the application. + * + * @param callbacks A pointer to the structure carrying callbacks. + * @return LORAWAN_STATUS_OK on success, a negative error code on failure. + */ + lorawan_status_t set_lora_callbacks(const lorawan_app_callbacks_t *callbacks); + + /** Connect OTAA or ABP using Mbed-OS config system + * + * @return For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed by + * a 'CONNECTED' event. Otherwise a negative error code is returned. + * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. + * + * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the first call. + * Any subsequent call will return either LORAWAN_STATUS_BUSY (if the previous request for connection + * is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). + * A 'CONNECTED' event is sent to the application when the JoinAccept is received. + */ + lorawan_status_t connect(); + + /** Connect OTAA or ABP with parameters + * + * @param connect Options for an end device connection to the gateway. + * + * @return For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed by + * a 'CONNECTED' event. Otherwise a negative error code is returned. + * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. + * + * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the first call. + * Any subsequent call will return either LORAWAN_STATUS_BUSY (if the previous request for connection + * is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). + * A 'CONNECTED' event is sent to the application when the JoinAccept is received. + */ + lorawan_status_t connect(const lorawan_connect_t &connect); + + /** Adds channels to use. + * + * You can provide a list of channels with appropriate parameters filled + * in. However, this list is not absolute. In some regions, a CF + * list gets implemented by default, which means that the network can overwrite your channel + * frequency settings right after receiving a Join Accept. You may try + * to set up any channel or channels after that and if the channel requested + * is already active, the request is silently ignored. A negative error + * code is returned if there is any problem with parameters. + * + * You need to ensure that the base station nearby supports the channel or channels being added. + * + * If your list includes a default channel (a channel where Join Requests + * are received) you cannot fully configure the channel parameters. + * Either leave the channel settings to default or check your + * corresponding PHY layer implementation. For example, LoRaPHYE868. + * + * @param channel_plan A list of channels or a single channel. + * + * @return LORAWAN_STATUS_OK on success, a negative error + * code on failure. + */ + lorawan_status_t add_channels(const lorawan_channelplan_t &channel_plan); + + /** Removes a channel from the list. + * + * @param channel_id Index of the channel being removed + * + * @return LORAWAN_STATUS_OK on success, a negative error + * code on failure. + */ + lorawan_status_t remove_a_channel(uint8_t channel_id); + + /** Removes a previously set channel plan. + * + * @return LORAWAN_STATUS_OK on success, a negative error + * code on failure. + */ + lorawan_status_t drop_channel_list(); + + /** Gets a list of currently enabled channels . + * + * @param channel_plan The channel plan structure to store final result. + * + * @return LORAWAN_STATUS_OK on success, a negative error + * code on failure. + */ + lorawan_status_t get_enabled_channels(lorawan_channelplan_t &channel_plan); + + /** Sets up a retry counter for confirmed messages. + * + * Valid only for confirmed messages. This API sets the number of times the + * stack will retry a CONFIRMED message before giving up and reporting an + * error. + * + * @param count The number of retries for confirmed messages. + * + * @return LORAWAN_STATUS_OK or a negative error code. + */ + lorawan_status_t set_confirmed_msg_retry(uint8_t count); + + /** Sets up the data rate. + * + * `set_datarate()` first verifies whether the data rate given is valid or not. + * If it is valid, the system sets the given data rate to the channel. + * + * @param data_rate The intended data rate, for example DR_0 or DR_1. + * Note that the macro DR_* can mean different + * things in different regions. + * + * @return LORAWAN_STATUS_OK if everything goes well, otherwise + * a negative error code. + */ + lorawan_status_t set_channel_data_rate(uint8_t data_rate); + + /** Enables ADR. + * + * @param adr_enabled 0 ADR disabled, 1 ADR enabled. + * + * @return LORAWAN_STATUS_OK on success, a negative error + * code on failure. + */ + lorawan_status_t enable_adaptive_datarate(bool adr_enabled); + + /** Send message to gateway + * + * @param port The application port number. Port numbers 0 and 224 + * are reserved, whereas port numbers from 1 to 223 + * (0x01 to 0xDF) are valid port numbers. + * Anything out of this range is illegal. + * + * @param data A pointer to the data being sent. The ownership of the + * buffer is not transferred. The data is copied to the + * internal buffers. + * + * @param length The size of data in bytes. + * + * @param flags A flag used to determine what type of + * message is being sent, for example: + * + * MSG_UNCONFIRMED_FLAG = 0x01 + * MSG_CONFIRMED_FLAG = 0x02 + * MSG_MULTICAST_FLAG = 0x04 + * MSG_PROPRIETARY_FLAG = 0x08 + * MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be + * used in conjunction with MSG_UNCONFIRMED_FLAG and + * MSG_CONFIRMED_FLAG depending on the intended use. + * + * MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set + * a confirmed message flag for a proprietary message. + * MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are + * mutually exclusive. + * + * @param null_allowed Internal use only. Needed for sending empty packet + * having CONFIRMED bit on. + * + * @param allow_port_0 Internal use only. Needed for flushing MAC commands. + * + * @return The number of bytes sent, or + * LORAWAN_STATUS_WOULD_BLOCK if another TX is + * ongoing, or a negative error code on failure. + */ + int16_t handle_tx(uint8_t port, const uint8_t *data, + uint16_t length, uint8_t flags, + bool null_allowed = false, bool allow_port_0 = false); + + /** Receives a message from the Network Server. + * + * @param data A pointer to buffer where the received data will be + * stored. + * + * @param length The size of data in bytes + * + * @param port The application port number. Port numbers 0 and 224 + * are reserved, whereas port numbers from 1 to 223 + * (0x01 to 0xDF) are valid port numbers. + * Anything out of this range is illegal. + * + * In return will contain the number of port to which + * message was received. + * + * @param flags A flag is used to determine what type of + * message is being received, for example: + * + * MSG_UNCONFIRMED_FLAG = 0x01, + * MSG_CONFIRMED_FLAG = 0x02 + * MSG_MULTICAST_FLAG = 0x04, + * MSG_PROPRIETARY_FLAG = 0x08 + * + * MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be + * used in conjunction with MSG_UNCONFIRMED_FLAG and + * MSG_CONFIRMED_FLAG depending on the intended use. + * + * MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set + * a confirmed message flag for a proprietary message. + * + * MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are + * not mutually exclusive, i.e., the user can subscribe to + * receive both CONFIRMED AND UNCONFIRMED messages at + * the same time. + * + * In return will contain the flags to determine what kind + * of message was received. + * + * @param validate_params If set to true, the given port and flags values will be checked + * against the values received with the message. If values do not + * match, LORAWAN_STATUS_WOULD_BLOCK will be returned. + * + * @return It could be one of these: + * i) 0 if there is nothing else to read. + * ii) Number of bytes written to user buffer. + * iii) LORAWAN_STATUS_WOULD_BLOCK if there is + * nothing available to read at the moment. + * iv) A negative error code on failure. + */ + int16_t handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params); + + /** Send Link Check Request MAC command. + * + * + * This API schedules a Link Check Request command (LinkCheckReq) for the network + * server and once the response, i.e., LinkCheckAns MAC command is received + * from the Network Server, an event is generated. + * + * A callback function for the link check response must be set prior to using + * this API, otherwise a LORAWAN_STATUS_PARAMETER_INVALID error is thrown. + * + * @return LORAWAN_STATUS_OK on successfully queuing a request, or + * a negative error code on failure. + * + */ + lorawan_status_t set_link_check_request(); + + /** Removes link check request sticky MAC command. + * + * Any already queued request may still get entertained. However, no new + * requests will be made. + */ + void remove_link_check_request(); + + /** Shuts down the LoRaWAN protocol. + * + * In response to the user call for disconnection, the stack shuts down itself. + * + * @return LORAWAN_STATUS_DEVICE_OFF on successfully shutdown. + */ + lorawan_status_t shutdown(); + + /** Change device class + * + * Change current device class. + * + * @param device_class The device class + * + * @return LORAWAN_STATUS_OK on success, + * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, + * or other negative error code if request failed. + */ + lorawan_status_t set_device_class(const device_class_t &device_class); + + /** Acquire TX meta-data + * + * Upon successful transmission, TX meta-data will be made available + * + * @param metadata A reference to the inbound structure which will be + * filled with any TX meta-data if available. + * + * @return LORAWAN_STATUS_OK if successful, + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise + */ + lorawan_status_t acquire_tx_metadata(lorawan_tx_metadata &metadata); + + /** Acquire RX meta-data + * + * Upon successful reception, RX meta-data will be made available + * + * @param metadata A reference to the inbound structure which will be + * filled with any RX meta-data if available. + * + * @return LORAWAN_STATUS_OK if successful, + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise + */ + lorawan_status_t acquire_rx_metadata(lorawan_rx_metadata &metadata); + + /** Acquire backoff meta-data + * + * Get hold of backoff time after which the transmission will take place. + * + * @param backoff A reference to the inbound integer which will be + * filled with any backoff meta-data if available. + * + * @return LORAWAN_STATUS_OK if successful, + * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise + */ + lorawan_status_t acquire_backoff_metadata(int &backoff); + + /** Stops sending + * + * Stop sending any outstanding messages if they are not yet queued for + * transmission, i.e., if the backoff timer is nhot elapsed yet. + * + * @return LORAWAN_STATUS_OK if the transmission is cancelled. + * LORAWAN_STATUS_BUSY otherwise. + */ + lorawan_status_t stop_sending(void); + + void lock(void) + { + _loramac.lock(); + } + void unlock(void) + { + _loramac.unlock(); + } + +private: + typedef mbed::ScopedLock Lock; + /** + * Checks if the user provided port is valid or not + */ + bool is_port_valid(uint8_t port, bool allow_port_0 = false); + + /** + * State machine for stack controller layer. + */ + lorawan_status_t state_controller(device_states_t new_state); + + /** + * Helpers for state controller + */ + void process_uninitialized_state(lorawan_status_t &op_status); + void process_idle_state(lorawan_status_t &op_status); + void process_connected_state(); + void process_connecting_state(lorawan_status_t &op_status); + void process_joining_state(lorawan_status_t &op_status); + void process_scheduling_state(lorawan_status_t &op_status); + void process_status_check_state(); + void process_shutdown_state(lorawan_status_t &op_status); + void state_machine_run_to_completion(void); + + /** + * Handles MLME indications + */ + void mlme_indication_handler(void); + + /** + * Handles an MLME confirmation + */ + void mlme_confirm_handler(void); + + /** + * Handles an MCPS confirmation + */ + void mcps_confirm_handler(void); + + /** + * Handles an MCPS indication + */ + void mcps_indication_handler(void); + + /** + * Sets up user application port + */ + lorawan_status_t set_application_port(uint8_t port, bool allow_port_0 = false); + + /** + * Handles connection internally + */ + lorawan_status_t handle_connect(bool is_otaa); + + + /** Send event to application. + * + * @param event The event to be sent. + */ + void send_event_to_application(const lorawan_event_t event) const; + + /** Send empty uplink message to network. + * + * Sends an empty confirmed message to gateway. + * + * @param port The event to be sent. + */ + void send_automatic_uplink_message(uint8_t port); + + /** + * TX interrupt handlers and corresponding processors + */ + void tx_interrupt_handler(void); + void tx_timeout_interrupt_handler(void); + void process_transmission(void); + void process_transmission_timeout(void); + + /** + * RX interrupt handlers and corresponding processors + */ + void rx_interrupt_handler(const uint8_t *payload, uint16_t size, int16_t rssi, + int8_t snr); + void rx_timeout_interrupt_handler(void); + void rx_error_interrupt_handler(void); + void process_reception(const uint8_t *payload, uint16_t size, int16_t rssi, + int8_t snr); + void process_reception_timeout(bool is_timeout); + + int convert_to_msg_flag(const mcps_type_t type); + + void make_tx_metadata_available(void); + void make_rx_metadata_available(void); + + void handle_scheduling_failure(void); + + void post_process_tx_with_reception(void); + void post_process_tx_no_reception(void); + +private: + LoRaMac _loramac; + radio_events_t radio_events; + device_states_t _device_current_state; + lorawan_app_callbacks_t _callbacks; + lorawan_session_t _lw_session; + loramac_tx_message_t _tx_msg; + loramac_rx_message_t _rx_msg; + lorawan_tx_metadata _tx_metadata; + lorawan_rx_metadata _rx_metadata; + uint8_t _num_retry; + uint8_t _qos_cnt; + uint32_t _ctrl_flags; + uint8_t _app_port; + bool _link_check_requested; + bool _automatic_uplink_ongoing; + core_util_atomic_flag _rx_payload_in_use; + uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD]; + events::EventQueue *_queue; + lorawan_time_t _tx_timestamp; +}; + +#endif /* LORAWANSTACK_H_ */ diff --git a/connectivity/lorawan/lorastack/mac/LoRaMac.cpp b/connectivity/lorawan/lorastack/mac/LoRaMac.cpp new file mode 100644 index 0000000..6f0f0b1 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMac.cpp @@ -0,0 +1,1991 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRa MAC layer implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include +#include "LoRaMac.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "LMAC" + +using namespace events; +using namespace mbed; + +/* + * LoRaWAN spec 6.2: AppKey is AES-128 key + */ +#define APPKEY_KEY_LENGTH 128 + +/*! + * Maximum length of the fOpts field + */ +#define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH 15 + +/*! + * LoRaMac duty cycle for the back-off procedure during the first hour. + */ +#define BACKOFF_DC_1_HOUR 100 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 10 hours. + */ +#define BACKOFF_DC_10_HOURS 1000 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 24 hours. + */ +#define BACKOFF_DC_24_HOURS 10000 + +/*! + * The frame direction definition for uplink communications. + */ +#define UP_LINK 0 + +/*! + * The frame direction definition for downlink communications. + */ +#define DOWN_LINK 1 + +LoRaMac::LoRaMac() + : _lora_time(), + _lora_phy(NULL), + _mac_commands(), + _channel_plan(), + _lora_crypto(), + _params(), + _ev_queue(NULL), + _mcps_indication(), + _mcps_confirmation(), + _mlme_indication(), + _mlme_confirmation(), + _ongoing_tx_msg(), + _is_nwk_joined(false), + _can_cancel_tx(true), + _continuous_rx2_window_open(false), + _device_class(CLASS_A), + _prev_qos_level(LORAWAN_DEFAULT_QOS), + _demod_ongoing(false) +{ + _params.is_rx_window_enabled = true; + _params.max_ack_timeout_retries = 1; + _params.ack_timeout_retry_counter = 1; + + reset_mcps_confirmation(); + reset_mlme_confirmation(); + reset_mcps_indication(); +} + +LoRaMac::~LoRaMac() +{ +} + +/*************************************************************************** + * Radio event callbacks - delegated to Radio driver * + **************************************************************************/ + +const loramac_mcps_confirm_t *LoRaMac::get_mcps_confirmation() const +{ + return &_mcps_confirmation; +} + +const loramac_mcps_indication_t *LoRaMac::get_mcps_indication() const +{ + return &_mcps_indication; +} + +const loramac_mlme_confirm_t *LoRaMac::get_mlme_confirmation() const +{ + return &_mlme_confirmation; +} + +const loramac_mlme_indication_t *LoRaMac::get_mlme_indication() const +{ + return &_mlme_indication; +} + +void LoRaMac::post_process_mlme_request() +{ + _mlme_confirmation.pending = false; +} + +void LoRaMac::post_process_mcps_req() +{ + _params.is_last_tx_join_request = false; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; + if (_mcps_confirmation.req_type == MCPS_CONFIRMED) { + // An MCPS request for a CONFIRMED message has received an ack + // in the downlink message + if (_mcps_confirmation.ack_received) { + _params.is_node_ack_requested = false; + _mcps_confirmation.ack_received = false; + _mcps_indication.is_ack_recvd = false; + } else { + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + } + + _params.ul_frame_counter++; + _params.adr_ack_counter++; + } else { + //UNCONFIRMED or PROPRIETARY + _params.ul_frame_counter++; + _params.adr_ack_counter++; + if (_params.sys_params.nb_trans > 1) { + _mcps_confirmation.nb_retries = _params.ul_nb_rep_counter; + } + } +} + +void LoRaMac::post_process_mcps_ind() +{ + _mcps_indication.pending = false; +} + +void LoRaMac::post_process_mlme_ind() +{ + _mlme_indication.pending = false; +} + +lorawan_time_t LoRaMac::get_current_time(void) +{ + return _lora_time.get_current_time(); +} + +rx_slot_t LoRaMac::get_current_slot(void) +{ + return _params.rx_slot; +} + +/** + * This part handles incoming frames in response to Radio RX Interrupt + */ +void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size) +{ + uint32_t mic = 0; + uint32_t mic_rx = 0; + + _mlme_confirmation.nb_retries = _params.join_request_trial_counter; + + if (0 != _lora_crypto.decrypt_join_frame(payload + 1, size - 1, + _params.keys.app_key, APPKEY_KEY_LENGTH, + _params.rx_buffer + 1)) { + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + return; + } + + _params.rx_buffer[0] = payload[0]; + + if (_lora_crypto.compute_join_frame_mic(_params.rx_buffer, + size - LORAMAC_MFR_LEN, + _params.keys.app_key, + APPKEY_KEY_LENGTH, + &mic) != 0) { + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + return; + } + + mic_rx |= (uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN]; + mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 1] << 8); + mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 2] << 16); + mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 3] << 24); + + if (mic_rx == mic) { + _lora_time.stop(_params.timers.rx_window2_timer); + if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key, + APPKEY_KEY_LENGTH, + _params.rx_buffer + 1, + _params.dev_nonce, + _params.keys.nwk_skey, + _params.keys.app_skey) != 0) { + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + return; + } + + _params.net_id = (uint32_t) _params.rx_buffer[4]; + _params.net_id |= ((uint32_t) _params.rx_buffer[5] << 8); + _params.net_id |= ((uint32_t) _params.rx_buffer[6] << 16); + + _params.dev_addr = (uint32_t) _params.rx_buffer[7]; + _params.dev_addr |= ((uint32_t) _params.rx_buffer[8] << 8); + _params.dev_addr |= ((uint32_t) _params.rx_buffer[9] << 16); + _params.dev_addr |= ((uint32_t) _params.rx_buffer[10] << 24); + + _params.sys_params.rx1_dr_offset = (_params.rx_buffer[11] >> 4) & 0x07; + _params.sys_params.rx2_channel.datarate = _params.rx_buffer[11] & 0x0F; + + _params.sys_params.recv_delay1 = (_params.rx_buffer[12] & 0x0F); + + if (_params.sys_params.recv_delay1 == 0) { + _params.sys_params.recv_delay1 = 1; + } + + _params.sys_params.recv_delay1 *= 1000; + _params.sys_params.recv_delay2 = _params.sys_params.recv_delay1 + 1000; + + // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC + _lora_phy->apply_cf_list(&_params.rx_buffer[13], size - 17); + + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; + _is_nwk_joined = true; + // Node joined successfully + _params.ul_frame_counter = 0; + _params.ul_nb_rep_counter = 0; + _params.adr_ack_counter = 0; + + } else { + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; + } +} + +void LoRaMac::check_frame_size(uint16_t size) +{ + uint8_t value = _lora_phy->get_max_payload(_mcps_indication.rx_datarate, + _params.is_repeater_supported); + + if (MAX(0, (int16_t)((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD)) + > (int32_t) value) { + tr_error("Invalid frame size"); + } +} + +bool LoRaMac::message_integrity_check(const uint8_t *const payload, + const uint16_t size, + uint8_t *const ptr_pos, + uint32_t address, + uint32_t *downlink_counter, + const uint8_t *nwk_skey) +{ + uint32_t mic = 0; + uint32_t mic_rx = 0; + + uint16_t sequence_counter = 0; + uint16_t sequence_counter_prev = 0; + uint16_t sequence_counter_diff = 0; + + sequence_counter = (uint16_t) payload[(*ptr_pos)++]; + sequence_counter |= (uint16_t) payload[(*ptr_pos)++] << 8; + + mic_rx |= (uint32_t) payload[size - LORAMAC_MFR_LEN]; + mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 1] << 8); + mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 2] << 16); + mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 3] << 24); + + sequence_counter_prev = (uint16_t) * downlink_counter; + sequence_counter_diff = sequence_counter - sequence_counter_prev; + *downlink_counter += sequence_counter_diff; + + if (sequence_counter_diff >= _lora_phy->get_maximum_frame_counter_gap()) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOST; + _mcps_indication.dl_frame_counter = *downlink_counter; + return false; + } + + // sizeof nws_skey must be the same as _params.keys.nwk_skey, + _lora_crypto.compute_mic(payload, size - LORAMAC_MFR_LEN, + nwk_skey, + sizeof(_params.keys.nwk_skey) * 8, + address, DOWN_LINK, *downlink_counter, &mic); + + if (mic_rx != mic) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; + return false; + } + + return true; +} + +void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload, + uint16_t size, + uint8_t fopts_len, + uint8_t *nwk_skey, + uint8_t *app_skey, + uint32_t address, + uint32_t downlink_counter, + int16_t rssi, + int8_t snr) +{ + uint8_t frame_len = 0; + uint8_t payload_start_index = 8 + fopts_len; + uint8_t port = payload[payload_start_index++]; + frame_len = (size - 4) - payload_start_index; + + _mcps_indication.port = port; + + // special handling of control port 0 + if (port == 0) { + if (fopts_len == 0) { + // sizeof nws_skey must be the same as _params.keys.nwk_skey, + if (_lora_crypto.decrypt_payload(payload + payload_start_index, + frame_len, + nwk_skey, + sizeof(_params.keys.nwk_skey) * 8, + address, + DOWN_LINK, + downlink_counter, + _params.rx_buffer) != 0) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + } + + if (_mac_commands.process_mac_commands(_params.rx_buffer, 0, frame_len, + snr, _mlme_confirmation, + _params.sys_params, *_lora_phy) + != LORAWAN_STATUS_OK) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + return; + } + + if (_mac_commands.has_sticky_mac_cmd()) { + set_mlme_schedule_ul_indication(); + _mac_commands.clear_sticky_mac_cmd(); + } + + return; + } + + _mcps_indication.pending = false; + _mcps_confirmation.ack_received = false; + _mcps_indication.is_ack_recvd = false; + + return; + } + + // normal unicast/multicast port handling + if (fopts_len > 0) { + // Decode Options field MAC commands. Omit the fPort. + if (_mac_commands.process_mac_commands(payload, 8, + payload_start_index - 1, + snr, + _mlme_confirmation, + _params.sys_params, + *_lora_phy) != LORAWAN_STATUS_OK) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + return; + } + + if (_mac_commands.has_sticky_mac_cmd()) { + set_mlme_schedule_ul_indication(); + _mac_commands.clear_sticky_mac_cmd(); + } + } + + // sizeof app_skey must be the same as _params.keys.app_skey + if (_lora_crypto.decrypt_payload(payload + payload_start_index, + frame_len, + app_skey, + sizeof(_params.keys.app_skey) * 8, + address, + DOWN_LINK, + downlink_counter, + _params.rx_buffer) != 0) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + } else { + _mcps_indication.buffer = _params.rx_buffer; + _mcps_indication.buffer_size = frame_len; + _mcps_indication.is_data_recvd = true; + } +} + +void LoRaMac::extract_mac_commands_only(const uint8_t *payload, + int8_t snr, + uint8_t fopts_len) +{ + uint8_t payload_start_index = 8 + fopts_len; + if (fopts_len > 0) { + if (_mac_commands.process_mac_commands(payload, 8, payload_start_index, + snr, _mlme_confirmation, + _params.sys_params, *_lora_phy) + != LORAWAN_STATUS_OK) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + return; + } + + if (_mac_commands.has_sticky_mac_cmd()) { + set_mlme_schedule_ul_indication(); + _mac_commands.clear_sticky_mac_cmd(); + } + } +} + +void LoRaMac::handle_data_frame(const uint8_t *const payload, + const uint16_t size, + uint8_t ptr_pos, + uint8_t msg_type, + int16_t rssi, + int8_t snr) +{ + check_frame_size(size); + + bool is_multicast = false; + loramac_frame_ctrl_t fctrl; + multicast_params_t *cur_multicast_params; + uint32_t address = 0; + uint32_t downlink_counter = 0; + uint8_t app_payload_start_index = 0; + uint8_t *nwk_skey = _params.keys.nwk_skey; + uint8_t *app_skey = _params.keys.app_skey; + + address = payload[ptr_pos++]; + address |= ((uint32_t) payload[ptr_pos++] << 8); + address |= ((uint32_t) payload[ptr_pos++] << 16); + address |= ((uint32_t) payload[ptr_pos++] << 24); + + if (address != _params.dev_addr) { + // check if Multicast is destined for us + cur_multicast_params = _params.multicast_channels; + + while (cur_multicast_params != NULL) { + if (address == cur_multicast_params->address) { + is_multicast = true; + nwk_skey = cur_multicast_params->nwk_skey; + app_skey = cur_multicast_params->app_skey; + downlink_counter = cur_multicast_params->dl_frame_counter; + break; + } + + cur_multicast_params = cur_multicast_params->next; + } + + if (!is_multicast) { + // We are not the destination of this frame. + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; + _mcps_indication.pending = false; + return; + } + } else { + is_multicast = false; + nwk_skey = _params.keys.nwk_skey; + app_skey = _params.keys.app_skey; + downlink_counter = _params.dl_frame_counter; + } + + fctrl.value = payload[ptr_pos++]; + app_payload_start_index = 8 + fctrl.bits.fopts_len; + + //perform MIC check + if (!message_integrity_check(payload, size, &ptr_pos, address, + &downlink_counter, nwk_skey)) { + tr_error("MIC failed"); + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; + _mcps_indication.pending = false; + return; + } + + _mcps_confirmation.ack_received = false; + _mcps_indication.is_ack_recvd = false; + _mcps_indication.pending = true; + _mcps_indication.is_data_recvd = false; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_indication.multicast = is_multicast; + _mcps_indication.fpending_status = fctrl.bits.fpending; + _mcps_indication.buffer = NULL; + _mcps_indication.buffer_size = 0; + _mcps_indication.dl_frame_counter = downlink_counter; + _mcps_indication.rssi = rssi; + _mcps_indication.snr = snr; + + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; + + _params.adr_ack_counter = 0; + _mac_commands.clear_repeat_buffer(); + _mac_commands.clear_command_buffer(); + + if (is_multicast) { + _mcps_indication.type = MCPS_MULTICAST; + + // Discard if its a repeated message + if ((cur_multicast_params->dl_frame_counter == downlink_counter) + && (cur_multicast_params->dl_frame_counter != 0)) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + _mcps_indication.dl_frame_counter = downlink_counter; + _mcps_indication.pending = false; + + return; + } + + cur_multicast_params->dl_frame_counter = downlink_counter; + + } else { + if (msg_type == FRAME_TYPE_DATA_CONFIRMED_DOWN) { + _params.is_srv_ack_requested = true; + _mcps_indication.type = MCPS_CONFIRMED; + + if ((_params.dl_frame_counter == downlink_counter) + && (_params.dl_frame_counter != 0)) { + // Duplicated confirmed downlink. Skip indication. + // In this case, the MAC layer shall accept the MAC commands + // which are included in the downlink retransmission. + // It should not provide the same frame to the application + // layer again. The MAC layer accepts the acknowledgement. + tr_debug("Discarding duplicate frame"); + _mcps_indication.pending = false; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + + return; + } + } else if (msg_type == FRAME_TYPE_DATA_UNCONFIRMED_DOWN) { + _params.is_srv_ack_requested = false; + _mcps_indication.type = MCPS_UNCONFIRMED; + + if ((_params.dl_frame_counter == downlink_counter) + && (_params.dl_frame_counter != 0)) { + tr_debug("Discarding duplicate frame"); + _mcps_indication.pending = false; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + + return; + } + } + _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) { + _mcps_confirmation.ack_received = fctrl.bits.ack; + _mcps_indication.is_ack_recvd = fctrl.bits.ack; + } + + uint8_t frame_len = (size - 4) - app_payload_start_index; + + if (frame_len > 0) { + extract_data_and_mac_commands(payload, size, fctrl.bits.fopts_len, + nwk_skey, app_skey, address, + downlink_counter, rssi, snr); + } else { + extract_mac_commands_only(payload, snr, fctrl.bits.fopts_len); + } + + // Handle proprietary messages. + if (msg_type == FRAME_TYPE_PROPRIETARY) { + memcpy(_params.rx_buffer, &payload[ptr_pos], size); + + _mcps_indication.type = MCPS_PROPRIETARY; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_indication.buffer = _params.rx_buffer; + _mcps_indication.buffer_size = size - ptr_pos; + } + + // only stop act timer, if the ack is actually recieved + if (_mcps_confirmation.ack_received) { + _lora_time.stop(_params.timers.ack_timeout_timer); + } + + channel_params_t *list = _lora_phy->get_phy_channels(); + _mcps_indication.channel = list[_params.channel].frequency; + + if (get_current_slot() == RX_SLOT_WIN_1) { + _mcps_indication.rx_toa = _lora_phy->get_rx_time_on_air(_params.rx_window1_config.modem_type, + _mcps_indication.buffer_size); + } else { + _mcps_indication.rx_toa = _lora_phy->get_rx_time_on_air(_params.rx_window2_config.modem_type, + _mcps_indication.buffer_size); + } +} + +void LoRaMac::set_batterylevel_callback(mbed::Callback battery_level) +{ + _mac_commands.set_batterylevel_callback(battery_level); +} + +void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp) +{ + if (_device_class == CLASS_C) { + // this will open a continuous RX2 window until time==RECV_DELAY1 + open_rx2_window(); + } else { + _lora_phy->put_radio_to_sleep(); + } + + if ((_mcps_confirmation.req_type == MCPS_UNCONFIRMED) + && (_params.sys_params.nb_trans > 1)) { + //MBED_ASSERT(_params.ul_nb_rep_counter <= _params.sys_params.nb_trans); + _params.ul_nb_rep_counter++; + } + + if (_params.is_rx_window_enabled == true) { + lorawan_time_t time_diff = _lora_time.get_current_time() - timestamp; + // start timer after which rx1_window will get opened + _lora_time.start(_params.timers.rx_window1_timer, + _params.rx_window1_delay - time_diff); + + // start timer after which rx2_window will get opened + _lora_time.start(_params.timers.rx_window2_timer, + _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_ms); + } + + // start timer after which ack wait will timeout (for Confirmed messages) + if (_params.is_node_ack_requested) { + _lora_time.start(_params.timers.ack_timeout_timer, + (_params.rx_window2_delay - time_diff) + + _params.rx_window2_config.window_timeout_ms + + _lora_phy->get_ack_timeout()); + } + } else { + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + } + + _params.last_channel_idx = _params.channel; + + _lora_phy->set_last_tx_done(_params.channel, _is_nwk_joined, timestamp); + + _params.timers.aggregated_last_tx_time = timestamp; + + _mac_commands.clear_command_buffer(); +} + +void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size, + int16_t rssi, int8_t snr) +{ + _demod_ongoing = false; + if (_device_class == CLASS_C && !_continuous_rx2_window_open) { + _lora_time.stop(_rx2_closure_timer_for_class_c); + open_rx2_window(); + } else if (_device_class != CLASS_C) { + _lora_time.stop(_params.timers.rx_window1_timer); + _lora_phy->put_radio_to_sleep(); + } + + loramac_mhdr_t mac_hdr; + uint8_t pos = 0; + mac_hdr.value = payload[pos++]; + + switch (mac_hdr.bits.mtype) { + + case FRAME_TYPE_JOIN_ACCEPT: + + if (nwk_joined()) { + _mlme_confirmation.pending = false; + return; + } else { + handle_join_accept_frame(payload, size); + _mlme_confirmation.pending = true; + } + + break; + + case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: + case FRAME_TYPE_DATA_CONFIRMED_DOWN: + case FRAME_TYPE_PROPRIETARY: + + handle_data_frame(payload, size, pos, mac_hdr.bits.mtype, rssi, snr); + + break; + + default: + // This can happen e.g. if we happen to receive uplink of another device + // during the receive window. Block RX2 window since it can overlap with + // QOS TX and cause a mess. + tr_debug("RX unexpected mtype %u", mac_hdr.bits.mtype); + if (get_current_slot() == RX_SLOT_WIN_1) { + _lora_time.stop(_params.timers.rx_window2_timer); + } + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; + _mcps_indication.pending = false; + break; + } +} + +void LoRaMac::on_radio_tx_timeout(void) +{ + _lora_time.stop(_params.timers.rx_window1_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); + + if (_device_class == CLASS_C) { + open_rx2_window(); + } else { + _lora_phy->put_radio_to_sleep(); + } + + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + + _mac_commands.clear_command_buffer(); + + 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.tx_toa = 0; +} + +void LoRaMac::on_radio_rx_timeout(bool is_timeout) +{ + _demod_ongoing = false; + if (_device_class == CLASS_A) { + _lora_phy->put_radio_to_sleep(); + } + + if (_params.rx_slot == RX_SLOT_WIN_1) { + if (_params.is_node_ack_requested == true) { + _mcps_confirmation.status = is_timeout ? + LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT : + LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + } + _mlme_confirmation.status = is_timeout ? + LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT : + LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + + if (_device_class != CLASS_C) { + if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { + _lora_time.stop(_params.timers.rx_window2_timer); + } + } + } else { + if (_params.is_node_ack_requested == true) { + _mcps_confirmation.status = is_timeout ? + LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT : + LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + } + + _mlme_confirmation.status = is_timeout ? + LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT : + LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + } +} + +bool LoRaMac::continue_joining_process() +{ + if (_params.join_request_trial_counter >= _params.max_join_request_trials) { + return false; + } + + // Schedule a retry + if (handle_retransmission() != LORAWAN_STATUS_CONNECT_IN_PROGRESS) { + return false; + } + + return true; +} + +bool LoRaMac::continue_sending_process() +{ + if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { + _lora_time.stop(_params.timers.ack_timeout_timer); + return false; + } + + // retransmission will be handled in on_ack_timeout() whence the ACK timeout + // gets fired + return true; +} + +lorawan_status_t LoRaMac::send_join_request() +{ + lorawan_status_t status = LORAWAN_STATUS_OK; + loramac_mhdr_t mac_hdr; + loramac_frame_ctrl_t fctrl; + + _params.sys_params.channel_data_rate = + _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); + + mac_hdr.value = 0; + mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ; + + fctrl.value = 0; + fctrl.bits.adr = _params.sys_params.adr_on; + _params.is_last_tx_join_request = true; + + /* In case of join request retransmissions, the stack must prepare + * the frame again, because the network server keeps track of the random + * LoRaMacDevNonce values to prevent reply attacks. */ + status = prepare_frame(&mac_hdr, &fctrl, 0, NULL, 0); + + if (status == LORAWAN_STATUS_OK) { + if (schedule_tx() == LORAWAN_STATUS_OK) { + status = LORAWAN_STATUS_CONNECT_IN_PROGRESS; + } + } else { + tr_error("Couldn't send a JoinRequest: error %d", status); + } + + return status; +} + +/** + * This function handles retransmission of failed or unacknowledged + * outgoing traffic + */ +lorawan_status_t LoRaMac::handle_retransmission() +{ + if (!nwk_joined() && (_mlme_confirmation.req_type == MLME_JOIN)) { + return send_join_request(); + } + + return schedule_tx(); +} + +/** + * This function is called when the backoff_timer gets fired. + * It is used for re-scheduling an unsent packet in the pipe. This packet + * can be a Join Request or any other data packet. + */ +void LoRaMac::on_backoff_timer_expiry(void) +{ + Lock lock(*this); + + _lora_time.stop(_params.timers.backoff_timer); + + if ((schedule_tx() != LORAWAN_STATUS_OK) && nwk_joined()) { + _scheduling_failure_handler.call(); + } +} + +void LoRaMac::open_rx1_window(void) +{ + Lock lock(*this); + _demod_ongoing = true; + _continuous_rx2_window_open = false; + _lora_time.stop(_params.timers.rx_window1_timer); + _params.rx_slot = RX_SLOT_WIN_1; + + channel_params_t *active_channel_list = _lora_phy->get_phy_channels(); + _params.rx_window1_config.channel = _params.channel; + _params.rx_window1_config.frequency = active_channel_list[_params.channel].frequency; + // Apply the alternative RX 1 window frequency, if it is available + if (active_channel_list[_params.channel].rx1_frequency != 0) { + _params.rx_window1_config.frequency = active_channel_list[_params.channel].rx1_frequency; + } + _params.rx_window1_config.dr_offset = _params.sys_params.rx1_dr_offset; + _params.rx_window1_config.dl_dwell_time = _params.sys_params.downlink_dwell_time; + _params.rx_window1_config.is_repeater_supported = _params.is_repeater_supported; + _params.rx_window1_config.is_rx_continuous = false; + _params.rx_window1_config.rx_slot = _params.rx_slot; + + if (_device_class == CLASS_C) { + _lora_phy->put_radio_to_standby(); + } + + _mcps_indication.rx_datarate = _params.rx_window1_config.datarate; + + _lora_phy->rx_config(&_params.rx_window1_config); + _lora_phy->handle_receive(); + + tr_debug("RX1 slot open, Freq = %lu", _params.rx_window1_config.frequency); +} + +void LoRaMac::open_rx2_window() +{ + if (_demod_ongoing) { + tr_info("RX1 Demodulation ongoing, skip RX2 window opening"); + return; + } + Lock lock(*this); + _continuous_rx2_window_open = true; + _lora_time.stop(_params.timers.rx_window2_timer); + + _params.rx_window2_config.channel = _params.channel; + _params.rx_window2_config.frequency = _params.sys_params.rx2_channel.frequency; + _params.rx_window2_config.dl_dwell_time = _params.sys_params.downlink_dwell_time; + _params.rx_window2_config.is_repeater_supported = _params.is_repeater_supported; + + if (get_device_class() == CLASS_C) { + _params.rx_window2_config.is_rx_continuous = true; + } else { + _params.rx_window2_config.is_rx_continuous = false; + } + + _params.rx_window2_config.rx_slot = _params.rx_window2_config.is_rx_continuous ? + RX_SLOT_WIN_CLASS_C : RX_SLOT_WIN_2; + + _mcps_indication.rx_datarate = _params.rx_window2_config.datarate; + + _lora_phy->rx_config(&_params.rx_window2_config); + _lora_phy->handle_receive(); + _params.rx_slot = _params.rx_window2_config.rx_slot; + + tr_debug("RX2 slot open, Freq = %lu", _params.rx_window2_config.frequency); +} + +void LoRaMac::on_ack_timeout_timer_event(void) +{ + Lock lock(*this); + + if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { + return; + } + + tr_debug("ACK_TIMEOUT Elapses, Retrying ..."); + _lora_time.stop(_params.timers.ack_timeout_timer); + + // reduce data rate on every 2nd attempt if and only if the + // ADR is on + if ((_params.ack_timeout_retry_counter % 2) + && (_params.sys_params.adr_on)) { + tr_debug("Trading datarate for range"); + _params.sys_params.channel_data_rate = _lora_phy->get_next_lower_tx_datarate(_params.sys_params.channel_data_rate); + } + + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; + + + // Schedule a retry + lorawan_status_t status = handle_retransmission(); + + if (status == LORAWAN_STATUS_NO_CHANNEL_FOUND || + status == LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND) { + // In a case when enabled channels are not found, PHY layer + // resorts to default channels. Next attempt should go forward as the + // default channels are always available if there is a base station in the + // vicinity. Otherwise something is wrong with the stack, we should assert + // here + _mac_commands.clear_command_buffer(); + _params.is_node_ack_requested = false; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; + + // For the next attempt we need to make sure that we do not incur length error + // which would mean that the datarate changed during retransmissions and + // the original packet doesn't fit into allowed payload buffer anymore. + status = handle_retransmission(); + + if (status == LORAWAN_STATUS_LENGTH_ERROR) { + _scheduling_failure_handler.call(); + return; + } + + // if we did not incur a length error and still the status is not OK, + // it is a critical failure + status = handle_retransmission(); + MBED_ASSERT(status == LORAWAN_STATUS_OK); + (void) status; + } else if (status != LORAWAN_STATUS_OK) { + _scheduling_failure_handler.call(); + return; + } + + _params.ack_timeout_retry_counter++; +} + +bool LoRaMac::validate_payload_length(uint16_t length, + int8_t datarate, + uint8_t fopts_len) +{ + uint16_t max_value = 0; + uint16_t payloadSize = 0; + + max_value = _lora_phy->get_max_payload(datarate, _params.is_repeater_supported); + + // Calculate the resulting payload size + payloadSize = (length + fopts_len); + + // Validation of the application payload size + if ((payloadSize <= max_value) && + (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) { + return true; + } + return false; +} + +void LoRaMac::set_mlme_schedule_ul_indication(void) +{ + _mlme_indication.indication_type = MLME_SCHEDULE_UPLINK; + _mlme_indication.pending = true; +} + +// This is not actual transmission. It just schedules a message in response +// to MCPS request +lorawan_status_t LoRaMac::send(loramac_mhdr_t *machdr, const uint8_t fport, + const void *fbuffer, uint16_t fbuffer_size) +{ + loramac_frame_ctrl_t fctrl; + + fctrl.value = 0; + fctrl.bits.fopts_len = 0; + fctrl.bits.fpending = 0; + fctrl.bits.ack = false; + fctrl.bits.adr_ack_req = false; + fctrl.bits.adr = _params.sys_params.adr_on; + + lorawan_status_t status = prepare_frame(machdr, &fctrl, fport, fbuffer, + fbuffer_size); + + if (status != LORAWAN_STATUS_OK) { + return status; + } + + // Reset confirm parameters + _mcps_confirmation.nb_retries = 0; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.ul_frame_counter = _params.ul_frame_counter; + + status = schedule_tx(); + + return status; +} + +int LoRaMac::get_backoff_timer_event_id(void) +{ + return _params.timers.backoff_timer.timer_id; +} + +lorawan_status_t LoRaMac::clear_tx_pipe(void) +{ + if (!_can_cancel_tx) { + return LORAWAN_STATUS_BUSY; + } + + // check if the event is not already queued + const int id = get_backoff_timer_event_id(); + + if (id == 0) { + // No queued send request + return LORAWAN_STATUS_NO_OP; + } + + if (_ev_queue->time_left(id) > 0) { + _lora_time.stop(_params.timers.backoff_timer); + _lora_time.stop(_params.timers.ack_timeout_timer); + memset(_params.tx_buffer, 0, sizeof _params.tx_buffer); + _params.tx_buffer_len = 0; + reset_ongoing_tx(true); + tr_debug("Sending Cancelled"); + return LORAWAN_STATUS_OK; + } else { + // Event is already being dispatched so it cannot be cancelled + return LORAWAN_STATUS_BUSY; + } +} + +lorawan_status_t LoRaMac::schedule_tx() +{ + channel_selection_params_t next_channel; + lorawan_time_t backoff_time = 0; + lorawan_time_t aggregated_timeoff = 0; + uint8_t channel = 0; + uint8_t fopts_len = 0; + + if (_params.sys_params.max_duty_cycle == 255) { + return LORAWAN_STATUS_DEVICE_OFF; + } + + if (_params.sys_params.max_duty_cycle == 0) { + _params.timers.aggregated_timeoff = 0; + } + + if (MBED_CONF_LORA_DUTY_CYCLE_ON && _lora_phy->verify_duty_cycle(true)) { + _params.is_dutycycle_on = true; + } else { + _params.is_dutycycle_on = false; + } + + calculate_backOff(_params.last_channel_idx); + + next_channel.aggregate_timeoff = _params.timers.aggregated_timeoff; + next_channel.current_datarate = _params.sys_params.channel_data_rate; + next_channel.dc_enabled = _params.is_dutycycle_on; + next_channel.joined = _is_nwk_joined; + next_channel.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; + + lorawan_status_t status = _lora_phy->set_next_channel(&next_channel, + &channel, + &backoff_time, + &aggregated_timeoff); + + _params.channel = channel; + _params.timers.aggregated_timeoff = aggregated_timeoff; + + switch (status) { + case LORAWAN_STATUS_NO_CHANNEL_FOUND: + case LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND: + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + return status; + case LORAWAN_STATUS_DUTYCYCLE_RESTRICTED: + if (backoff_time != 0) { + tr_debug("DC enforced: Transmitting in %lu ms", backoff_time); + _can_cancel_tx = true; + _lora_time.start(_params.timers.backoff_timer, backoff_time); + } + return LORAWAN_STATUS_OK; + default: + break; + } + + uint8_t rx1_dr = _lora_phy->apply_DR_offset(_params.sys_params.channel_data_rate, + _params.sys_params.rx1_dr_offset); + + tr_debug("TX: Channel=%d, TX DR=%d, RX1 DR=%d", + _params.channel, _params.sys_params.channel_data_rate, rx1_dr); + + + _lora_phy->compute_rx_win_params(rx1_dr, MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, + MBED_CONF_LORA_MAX_SYS_RX_ERROR, + &_params.rx_window1_config); + + _lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate, + MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, + MBED_CONF_LORA_MAX_SYS_RX_ERROR, + &_params.rx_window2_config); + + if (!_is_nwk_joined) { + _params.rx_window1_delay = _params.sys_params.join_accept_delay1 + + _params.rx_window1_config.window_offset; + _params.rx_window2_delay = _params.sys_params.join_accept_delay2 + + _params.rx_window2_config.window_offset; + } else { + + // if the outgoing message is a proprietary message, it doesn't include any + // standard message formatting except port and MHDR. + if (_ongoing_tx_msg.type == MCPS_PROPRIETARY) { + fopts_len = 0; + } else { + fopts_len = _mac_commands.get_mac_cmd_length() + _mac_commands.get_repeat_commands_length(); + } + + // A check was performed for validity of FRMPayload in ::prepare_ongoing_tx() API. + // However, owing to the asynch nature of the send() API, we should check the + // validity again, as datarate may have changed since we last attempted to transmit. + if (validate_payload_length(_ongoing_tx_msg.f_buffer_size, + _params.sys_params.channel_data_rate, + fopts_len) == false) { + tr_error("Allowed FRMPayload = %d, FRMPayload = %d, MAC commands pending = %d", + _lora_phy->get_max_payload(_params.sys_params.channel_data_rate, + _params.is_repeater_supported), + _ongoing_tx_msg.f_buffer_size, fopts_len); + return LORAWAN_STATUS_LENGTH_ERROR; + } + _params.rx_window1_delay = _params.sys_params.recv_delay1 + + _params.rx_window1_config.window_offset; + _params.rx_window2_delay = _params.sys_params.recv_delay2 + + _params.rx_window2_config.window_offset; + } + + // handle the ack to the server here so that if the sending was cancelled + // by the user in the backoff period, we would still ack the previous frame. + if (_params.is_srv_ack_requested) { + _params.is_srv_ack_requested = false; + } + + _can_cancel_tx = false; + return send_frame_on_channel(_params.channel); +} + +void LoRaMac::calculate_backOff(uint8_t channel) +{ + lorawan_time_t elapsed_time = _lora_time.get_elapsed_time(_params.timers.mac_init_time); + _lora_phy->calculate_backoff(_is_nwk_joined, _params.is_last_tx_join_request, _params.is_dutycycle_on, + channel, elapsed_time, _params.timers.tx_toa); + + // Update aggregated time-off. This must be an assignment and no incremental + // update as we do only calculate the time-off based on the last transmission + _params.timers.aggregated_timeoff = (_params.timers.tx_toa * _params.sys_params.aggregated_duty_cycle + - _params.timers.tx_toa); +} + +void LoRaMac::reset_mac_parameters(void) +{ + _is_nwk_joined = false; + + _params.ul_frame_counter = 0; + _params.dl_frame_counter = 0; + _params.adr_ack_counter = 0; + + _params.ul_nb_rep_counter = 0; + + _params.max_ack_timeout_retries = 1; + _params.ack_timeout_retry_counter = 1; + _params.is_ack_retry_timeout_expired = false; + + _params.sys_params.max_duty_cycle = 0; + _params.sys_params.aggregated_duty_cycle = 1; + + _mac_commands.clear_command_buffer(); + _mac_commands.clear_repeat_buffer(); + + _params.is_rx_window_enabled = true; + + _lora_phy->reset_to_default_values(&_params, false); + + _params.is_node_ack_requested = false; + _params.is_srv_ack_requested = false; + + multicast_params_t *cur = _params.multicast_channels; + while (cur != NULL) { + cur->dl_frame_counter = 0; + cur = cur->next; + } + _params.channel = 0; + _params.last_channel_idx = _params.channel; + + _demod_ongoing = false; +} + +uint8_t LoRaMac::get_default_tx_datarate() +{ + return _lora_phy->get_default_tx_datarate(); +} + +void LoRaMac::enable_adaptive_datarate(bool adr_enabled) +{ + _params.sys_params.adr_on = adr_enabled; +} + +lorawan_status_t LoRaMac::set_channel_data_rate(uint8_t data_rate) +{ + if (_params.sys_params.adr_on) { + tr_error("Cannot set data rate. Please turn off ADR first."); + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + if (_lora_phy->verify_tx_datarate(data_rate, false) == true) { + _params.sys_params.channel_data_rate = data_rate; + } else { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + return LORAWAN_STATUS_OK; +} + +bool LoRaMac::tx_ongoing() +{ + return _ongoing_tx_msg.tx_ongoing; +} + +void LoRaMac::set_tx_ongoing(bool ongoing) +{ + _can_cancel_tx = true; + _ongoing_tx_msg.tx_ongoing = ongoing; +} + +void LoRaMac::reset_ongoing_tx(bool reset_pending) +{ + _ongoing_tx_msg.tx_ongoing = false; + memset(_ongoing_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE); + _ongoing_tx_msg.f_buffer_size = 0; + if (reset_pending) { + _ongoing_tx_msg.pending_size = 0; + } +} + +int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port, + const uint8_t *const data, + uint16_t length, + uint8_t flags, + uint8_t num_retries) +{ + _ongoing_tx_msg.port = port; + uint8_t max_possible_size = 0; + uint8_t fopts_len = _mac_commands.get_mac_cmd_length() + + _mac_commands.get_repeat_commands_length(); + + // Handles unconfirmed messages + if (flags & MSG_UNCONFIRMED_FLAG) { + _ongoing_tx_msg.type = MCPS_UNCONFIRMED; + _ongoing_tx_msg.fport = port; + _ongoing_tx_msg.nb_trials = 1; + } + + // Handles confirmed messages + if (flags & MSG_CONFIRMED_FLAG) { + _ongoing_tx_msg.type = MCPS_CONFIRMED; + _ongoing_tx_msg.fport = port; + _ongoing_tx_msg.nb_trials = num_retries; + } + + // Handles proprietary messages + if (flags & MSG_PROPRIETARY_FLAG) { + _ongoing_tx_msg.type = MCPS_PROPRIETARY; + _ongoing_tx_msg.fport = port; + _ongoing_tx_msg.nb_trials = _params.sys_params.nb_trans; + // a proprietary frame only includes an MHDR field which contains MTYPE field. + // Everything else is at the discretion of the implementer + fopts_len = 0; + } + + max_possible_size = get_max_possible_tx_size(fopts_len); + + if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) { + max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE; + } + + if (max_possible_size < length) { + tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes", + length, max_possible_size); + + _ongoing_tx_msg.pending_size = length - max_possible_size; + _ongoing_tx_msg.f_buffer_size = max_possible_size; + memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size); + } else { + _ongoing_tx_msg.f_buffer_size = length; + _ongoing_tx_msg.pending_size = 0; + if (length > 0) { + memcpy(_ongoing_tx_msg.f_buffer, data, length); + } + } + + tr_info("RTS = %u bytes, PEND = %u, Port: %u", + _ongoing_tx_msg.f_buffer_size, _ongoing_tx_msg.pending_size, + _ongoing_tx_msg.fport); + + return _ongoing_tx_msg.f_buffer_size; +} + +lorawan_status_t LoRaMac::send_ongoing_tx() +{ + lorawan_status_t status; + _params.is_last_tx_join_request = false; + int8_t datarate = _params.sys_params.channel_data_rate; + + // This prohibits the data rate going below the minimum value. + datarate = MAX(datarate, (int8_t)_lora_phy->get_minimum_tx_datarate()); + + loramac_mhdr_t machdr; + machdr.value = 0; + + reset_mcps_confirmation(); + + _params.ack_timeout_retry_counter = 1; + _params.max_ack_timeout_retries = 1; + + if (MCPS_UNCONFIRMED == _ongoing_tx_msg.type) { + machdr.bits.mtype = FRAME_TYPE_DATA_UNCONFIRMED_UP; + } else if (_ongoing_tx_msg.type == MCPS_CONFIRMED) { + machdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; + _params.max_ack_timeout_retries = _ongoing_tx_msg.nb_trials; + } else if (_ongoing_tx_msg.type == MCPS_PROPRIETARY) { + machdr.bits.mtype = FRAME_TYPE_PROPRIETARY; + } else { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + if (_params.sys_params.adr_on == false) { + if (_lora_phy->verify_tx_datarate(datarate, false) == true) { + _params.sys_params.channel_data_rate = datarate; + } else { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + } + + status = send(&machdr, _ongoing_tx_msg.fport, _ongoing_tx_msg.f_buffer, + _ongoing_tx_msg.f_buffer_size); + if (status == LORAWAN_STATUS_OK) { + _mcps_confirmation.req_type = _ongoing_tx_msg.type; + } + + return status; +} + +device_class_t LoRaMac::get_device_class() const +{ + return _device_class; +} + +void LoRaMac::set_device_class(const device_class_t &device_class, + mbed::Callbackrx2_would_be_closure_handler) +{ + _device_class = device_class; + _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) { + tr_debug("Changing device class to -> CLASS_A"); + _lora_phy->put_radio_to_sleep(); + } else if (CLASS_C == _device_class) { + _params.is_node_ack_requested = false; + _lora_phy->put_radio_to_sleep(); + _lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate, + MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, + MBED_CONF_LORA_MAX_SYS_RX_ERROR, + &_params.rx_window2_config); + } + + if (CLASS_C == _device_class) { + tr_debug("Changing device class to -> CLASS_C"); + open_rx2_window(); + } +} + +void LoRaMac::setup_link_check_request() +{ + reset_mlme_confirmation(); + + _mlme_confirmation.req_type = MLME_LINK_CHECK; + _mlme_confirmation.pending = true; + _mac_commands.add_link_check_req(); +} + +lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_otaa) +{ + if (params) { + if (is_otaa) { + if ((params->connection_u.otaa.dev_eui == NULL) + || (params->connection_u.otaa.app_eui == NULL) + || (params->connection_u.otaa.app_key == NULL) + || (params->connection_u.otaa.nb_trials == 0)) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + _params.keys.dev_eui = params->connection_u.otaa.dev_eui; + _params.keys.app_eui = params->connection_u.otaa.app_eui; + _params.keys.app_key = params->connection_u.otaa.app_key; + _params.max_join_request_trials = params->connection_u.otaa.nb_trials; + + if (!_lora_phy->verify_nb_join_trials(params->connection_u.otaa.nb_trials)) { + // Value not supported, get default + _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; + } + // Reset variable JoinRequestTrials + _params.join_request_trial_counter = 0; + + reset_mac_parameters(); + + _params.sys_params.channel_data_rate = + _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); + } else { + if ((params->connection_u.abp.dev_addr == 0) + || (params->connection_u.abp.nwk_id == 0) + || (params->connection_u.abp.nwk_skey == NULL) + || (params->connection_u.abp.app_skey == NULL)) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + _params.net_id = params->connection_u.abp.nwk_id; + _params.dev_addr = params->connection_u.abp.dev_addr; + + memcpy(_params.keys.nwk_skey, params->connection_u.abp.nwk_skey, + sizeof(_params.keys.nwk_skey)); + + memcpy(_params.keys.app_skey, params->connection_u.abp.app_skey, + sizeof(_params.keys.app_skey)); + } + } else { +#if MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION + const static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; + const static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; + const static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; + + _params.keys.app_eui = const_cast(app_eui); + _params.keys.dev_eui = const_cast(dev_eui); + _params.keys.app_key = const_cast(app_key); + _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; + + // Reset variable JoinRequestTrials + _params.join_request_trial_counter = 0; + + reset_mac_parameters(); + + _params.sys_params.channel_data_rate = + _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); + +#else + const static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; + const static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; + + _params.net_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK) >> 25; + _params.dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; + + memcpy(_params.keys.nwk_skey, nwk_skey, sizeof(_params.keys.nwk_skey)); + + memcpy(_params.keys.app_skey, app_skey, sizeof(_params.keys.app_skey)); +#endif + } + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMac::join(bool is_otaa) +{ + if (!is_otaa) { + set_nwk_joined(true); + return LORAWAN_STATUS_OK; + } + + reset_mlme_confirmation(); + _mlme_confirmation.req_type = MLME_JOIN; + + return send_join_request(); +} + +static void memcpy_convert_endianess(uint8_t *dst, + const uint8_t *src, + uint16_t size) +{ + dst = dst + (size - 1); + while (size--) { + *dst-- = *src++; + } +} + +lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, + loramac_frame_ctrl_t *fctrl, + const uint8_t fport, + const void *fbuffer, + uint16_t fbuffer_size) +{ + uint16_t i; + uint8_t pkt_header_len = 0; + uint32_t mic = 0; + const void *payload = fbuffer; + uint8_t frame_port = fport; + lorawan_status_t status = LORAWAN_STATUS_OK; + + _params.tx_buffer_len = 0; + + _params.is_node_ack_requested = false; + + if (fbuffer == NULL) { + fbuffer_size = 0; + } + + _params.tx_buffer_len = fbuffer_size; + + _params.tx_buffer[pkt_header_len++] = machdr->value; + + switch (machdr->bits.mtype) { + + case FRAME_TYPE_JOIN_REQ: + + _params.tx_buffer_len = pkt_header_len; + memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len, + _params.keys.app_eui, 8); + _params.tx_buffer_len += 8; + memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len, + _params.keys.dev_eui, 8); + _params.tx_buffer_len += 8; + + _params.dev_nonce = _lora_phy->get_radio_rng(); + + _params.tx_buffer[_params.tx_buffer_len++] = _params.dev_nonce & 0xFF; + _params.tx_buffer[_params.tx_buffer_len++] = (_params.dev_nonce >> 8) & 0xFF; + + if (0 != _lora_crypto.compute_join_frame_mic(_params.tx_buffer, + _params.tx_buffer_len & 0xFF, + _params.keys.app_key, + APPKEY_KEY_LENGTH, + &mic)) { + return LORAWAN_STATUS_CRYPTO_FAIL; + } + + _params.tx_buffer[_params.tx_buffer_len++] = mic & 0xFF; + _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 8) & 0xFF; + _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 16) & 0xFF; + _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 24) & 0xFF; + + break; + case FRAME_TYPE_DATA_CONFIRMED_UP: + _params.is_node_ack_requested = true; + //Intentional fallthrough + case FRAME_TYPE_DATA_UNCONFIRMED_UP: { + if (!_is_nwk_joined) { + return LORAWAN_STATUS_NO_NETWORK_JOINED; + } + + if (_params.sys_params.adr_on) { + if (_lora_phy->get_next_ADR(true, + _params.sys_params.channel_data_rate, + _params.sys_params.channel_tx_power, + _params.adr_ack_counter)) { + fctrl->bits.adr_ack_req = 1; + } + } + + if (_params.is_srv_ack_requested == true) { + tr_debug("Acking to NS"); + fctrl->bits.ack = 1; + } + + _params.tx_buffer[pkt_header_len++] = (_params.dev_addr) & 0xFF; + _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 8) & 0xFF; + _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 16) & 0xFF; + _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 24) & 0xFF; + + _params.tx_buffer[pkt_header_len++] = fctrl->value; + + _params.tx_buffer[pkt_header_len++] = _params.ul_frame_counter & 0xFF; + _params.tx_buffer[pkt_header_len++] = (_params.ul_frame_counter >> 8) + & 0xFF; + + _mac_commands.copy_repeat_commands_to_buffer(); + + const uint8_t mac_commands_len = _mac_commands.get_mac_cmd_length(); + + if ((payload != NULL) && (_params.tx_buffer_len > 0)) { + if (mac_commands_len <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH) { + fctrl->bits.fopts_len += mac_commands_len; + + // Update FCtrl field with new value of OptionsLength + _params.tx_buffer[0x05] = fctrl->value; + + const uint8_t *buffer = _mac_commands.get_mac_commands_buffer(); + for (i = 0; i < mac_commands_len; i++) { + _params.tx_buffer[pkt_header_len++] = buffer[i]; + } + } else { + _params.tx_buffer_len = mac_commands_len; + payload = _mac_commands.get_mac_commands_buffer(); + frame_port = 0; + } + } else { + if (mac_commands_len > 0) { + _params.tx_buffer_len = mac_commands_len; + payload = _mac_commands.get_mac_commands_buffer(); + frame_port = 0; + } + } + + _mac_commands.parse_mac_commands_to_repeat(); + + // We always add Port Field. Spec leaves it optional. + _params.tx_buffer[pkt_header_len++] = frame_port; + + if ((payload != NULL) && (_params.tx_buffer_len > 0)) { + + uint8_t *key = _params.keys.app_skey; + uint32_t key_length = sizeof(_params.keys.app_skey) * 8; + if (frame_port == 0) { + key = _params.keys.nwk_skey; + key_length = sizeof(_params.keys.nwk_skey) * 8; + } + if (0 != _lora_crypto.encrypt_payload((uint8_t *) payload, _params.tx_buffer_len, + key, key_length, + _params.dev_addr, UP_LINK, + _params.ul_frame_counter, + &_params.tx_buffer[pkt_header_len])) { + status = LORAWAN_STATUS_CRYPTO_FAIL; + } + } + + _params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len; + + if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len, + _params.keys.nwk_skey, sizeof(_params.keys.nwk_skey) * 8, + _params.dev_addr, + UP_LINK, _params.ul_frame_counter, &mic)) { + status = LORAWAN_STATUS_CRYPTO_FAIL; + } + + _params.tx_buffer[_params.tx_buffer_len + 0] = mic & 0xFF; + _params.tx_buffer[_params.tx_buffer_len + 1] = (mic >> 8) & 0xFF; + _params.tx_buffer[_params.tx_buffer_len + 2] = (mic >> 16) & 0xFF; + _params.tx_buffer[_params.tx_buffer_len + 3] = (mic >> 24) & 0xFF; + + _params.tx_buffer_len += LORAMAC_MFR_LEN; + } + break; + case FRAME_TYPE_PROPRIETARY: + if ((fbuffer != NULL) && (_params.tx_buffer_len > 0)) { + memcpy(_params.tx_buffer + pkt_header_len, (uint8_t *) fbuffer, + _params.tx_buffer_len); + _params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len; + } + break; + default: + status = LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + tr_debug("Frame prepared to send at port %u", frame_port); + + return status; +} + +lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) +{ + tx_config_params_t tx_config; + int8_t tx_power = 0; + + tx_config.channel = channel; + tx_config.datarate = _params.sys_params.channel_data_rate; + tx_config.tx_power = _params.sys_params.channel_tx_power; + tx_config.max_eirp = _params.sys_params.max_eirp; + tx_config.antenna_gain = _params.sys_params.antenna_gain; + tx_config.pkt_len = _params.tx_buffer_len; + + _lora_phy->tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); + + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_confirmation.data_rate = _params.sys_params.channel_data_rate; + _mcps_confirmation.tx_power = tx_power; + _mcps_confirmation.channel = channel; + + _mcps_confirmation.tx_toa = _params.timers.tx_toa; + _mlme_confirmation.tx_toa = _params.timers.tx_toa; + + if (!_is_nwk_joined) { + _params.join_request_trial_counter++; + } + + _lora_phy->handle_send(_params.tx_buffer, _params.tx_buffer_len); + + return LORAWAN_STATUS_OK; +} + +void LoRaMac::reset_mcps_confirmation() +{ + memset((uint8_t *) &_mcps_confirmation, 0, sizeof(_mcps_confirmation)); + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; +} + +void LoRaMac::reset_mlme_confirmation() +{ + memset((uint8_t *) &_mlme_confirmation, 0, sizeof(_mlme_confirmation)); + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; +} + +void LoRaMac::reset_mcps_indication() +{ + memset((uint8_t *) &_mcps_indication, 0, sizeof(_mcps_indication)); + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; +} + +lorawan_status_t LoRaMac::initialize(EventQueue *queue, + mbed::Callbackscheduling_failure_handler) +{ + _lora_time.activate_timer_subsystem(queue); + _lora_phy->initialize(&_lora_time); + + _ev_queue = queue; + _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); + + _device_class = CLASS_A; + + _params.join_request_trial_counter = 0; + _params.max_join_request_trials = 1; + _params.is_repeater_supported = false; + + _params.timers.aggregated_last_tx_time = 0; + _params.timers.aggregated_timeoff = 0; + + _lora_phy->reset_to_default_values(&_params, true); + _params.sys_params.nb_trans = 1; + + reset_mac_parameters(); + + srand(_lora_phy->get_radio_rng()); + + _params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK; + _lora_phy->setup_public_network_mode(_params.is_nwk_public); + _lora_phy->put_radio_to_sleep(); + + _lora_time.init(_params.timers.backoff_timer, + mbed::callback(this, &LoRaMac::on_backoff_timer_expiry)); + _lora_time.init(_params.timers.rx_window1_timer, + mbed::callback(this, &LoRaMac::open_rx1_window)); + _lora_time.init(_params.timers.rx_window2_timer, + mbed::callback(this, &LoRaMac::open_rx2_window)); + _lora_time.init(_params.timers.ack_timeout_timer, + mbed::callback(this, &LoRaMac::on_ack_timeout_timer_event)); + + _params.timers.mac_init_time = _lora_time.get_current_time(); + + _params.sys_params.adr_on = MBED_CONF_LORA_ADR_ON; + _params.sys_params.channel_data_rate = _lora_phy->get_default_max_tx_datarate(); + + return LORAWAN_STATUS_OK; +} + +void LoRaMac::disconnect() +{ + _lora_time.stop(_params.timers.backoff_timer); + _lora_time.stop(_params.timers.rx_window1_timer); + _lora_time.stop(_params.timers.rx_window2_timer); + _lora_time.stop(_params.timers.ack_timeout_timer); + + _lora_phy->put_radio_to_sleep(); + + _is_nwk_joined = false; + _params.is_ack_retry_timeout_expired = false; + _params.is_rx_window_enabled = true; + _params.is_node_ack_requested = false; + _params.is_srv_ack_requested = false; + + _mac_commands.clear_command_buffer(); + _mac_commands.clear_repeat_buffer(); + + reset_mcps_confirmation(); + reset_mlme_confirmation(); + reset_mcps_indication(); +} + +uint8_t LoRaMac::get_max_possible_tx_size(uint8_t fopts_len) +{ + uint8_t max_possible_payload_size = 0; + uint8_t allowed_frm_payload_size = 0; + + int8_t datarate = _params.sys_params.channel_data_rate; + int8_t tx_power = _params.sys_params.channel_tx_power; + uint32_t adr_ack_counter = _params.adr_ack_counter; + + if (_params.sys_params.adr_on) { + // Just query the information. We do not want to apply them into use + // at this point. + _lora_phy->get_next_ADR(false, datarate, tx_power, adr_ack_counter); + } + + allowed_frm_payload_size = _lora_phy->get_max_payload(datarate, + _params.is_repeater_supported); + + if (allowed_frm_payload_size >= fopts_len) { + max_possible_payload_size = allowed_frm_payload_size - fopts_len; + } else { + max_possible_payload_size = allowed_frm_payload_size; + _mac_commands.clear_command_buffer(); + _mac_commands.clear_repeat_buffer(); + } + + return max_possible_payload_size; +} + +bool LoRaMac::nwk_joined() +{ + return _is_nwk_joined; +} + +void LoRaMac::set_nwk_joined(bool joined) +{ + _is_nwk_joined = joined; +} + +lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t &plan) +{ + if (tx_ongoing()) { + return LORAWAN_STATUS_BUSY; + } + + return _channel_plan.set_plan(plan); +} + +lorawan_status_t LoRaMac::remove_channel_plan() +{ + if (tx_ongoing()) { + return LORAWAN_STATUS_BUSY; + } + + return _channel_plan.remove_plan(); +} + +lorawan_status_t LoRaMac::get_channel_plan(lorawan_channelplan_t &plan) +{ + return _channel_plan.get_plan(plan, _lora_phy->get_phy_channels()); +} + +lorawan_status_t LoRaMac::remove_single_channel(uint8_t id) +{ + if (tx_ongoing()) { + return LORAWAN_STATUS_BUSY; + } + + return _channel_plan.remove_single_channel(id); +} + +lorawan_status_t LoRaMac::multicast_channel_link(multicast_params_t *channel_param) +{ + if (channel_param == NULL) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + if (tx_ongoing()) { + return LORAWAN_STATUS_BUSY; + } + + channel_param->dl_frame_counter = 0; + + if (_params.multicast_channels == NULL) { + _params.multicast_channels = channel_param; + } else { + multicast_params_t *cur = _params.multicast_channels; + while (cur->next != NULL) { + cur = cur->next; + } + cur->next = channel_param; + } + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMac::multicast_channel_unlink(multicast_params_t *channel_param) +{ + if (channel_param == NULL) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + if (tx_ongoing()) { + return LORAWAN_STATUS_BUSY; + } + + if (_params.multicast_channels != NULL) { + if (_params.multicast_channels == channel_param) { + _params.multicast_channels = channel_param->next; + } else { + multicast_params_t *cur = _params.multicast_channels; + + while (cur->next && cur->next != channel_param) { + cur = cur->next; + } + + if (cur->next) { + cur->next = channel_param->next; + } + } + channel_param->next = NULL; + } + + return LORAWAN_STATUS_OK; +} + +void LoRaMac::bind_phy(LoRaPHY &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; +} + diff --git a/connectivity/lorawan/lorastack/mac/LoRaMac.h b/connectivity/lorawan/lorastack/mac/LoRaMac.h new file mode 100644 index 0000000..977843d --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMac.h @@ -0,0 +1,706 @@ +/** + * \file LoRaMac.h + * + * \brief LoRa MAC layer implementation + * + * \copyright Revised BSD License, see LICENSE.TXT file include in the project + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) + * + * \defgroup LORAMAC LoRa MAC layer implementation + * This module specifies the API implementation of the LoRaMAC layer. + * This is a placeholder for a detailed description of the LoRaMac + * layer and the supported features. + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef MBED_LORAWAN_MAC_H__ +#define MBED_LORAWAN_MAC_H__ + +#include "events/EventQueue.h" + +#include "lorastack/phy/LoRaPHY.h" + +#include "system/LoRaWANTimer.h" +#include "system/lorawan_data_structures.h" + +#include "LoRaMacChannelPlan.h" +#include "LoRaMacCommand.h" +#include "LoRaMacCrypto.h" +#if MBED_CONF_RTOS_PRESENT +#include "rtos/Mutex.h" +#endif + +#include "platform/ScopedLock.h" + +/** LoRaMac Class + * Implementation of LoRaWAN MAC layer + */ +class LoRaMac { + +public: + + /** + * Constructor + */ + LoRaMac(); + + /** + * Destructor + */ + ~LoRaMac(); + + /** + * @brief LoRaMAC layer initialization + * + * @details Initializes the LoRaMAC layer, + * + * + * @param queue [in] A pointer to the application provided EventQueue. + * + * @param scheduling_failure_handler A callback to inform upper layer if a deferred + * transmission (after backoff or retry) fails to schedule. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t initialize(events::EventQueue *queue, + mbed::Callbackscheduling_failure_handler); + + /** + * @brief Disconnect LoRaMac layer + * + * @details Cancels all outstanding requests and sets LoRaMac's + * internal state to idle. + */ + void disconnect(void); + + /** + * @brief nwk_joined Checks if device has joined to network + * @return True if joined to network, false otherwise + */ + bool nwk_joined(); + + /** + * @brief Adds a channel plan to the system. + * + * @details Adds a whole channel plan or a single new channel if the plan + * contains only one channel and 'plan.nb_channels' is set to 1. + * Please note that this functionality is not available in all regions. + * Information on the allowed ranges is available at the + * LoRaWAN Regional Parameters V1.0.2rB. + * + * @param plan [in] A reference to application provided channel plan. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t add_channel_plan(const lorawan_channelplan_t &plan); + + /** + * @brief Removes a channel plan from the system. + * + * @details Removes the whole active channel plan except the 'Default Channels'. + * Please note that this functionality is not available in all regions. + * Information on the allowed ranges is available at the + * LoRaWAN Regional Parameters V1.0.2rB. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t remove_channel_plan(); + + /** + * @brief Access active channel plan. + * + * @details Provides access to the current active channel plan. + * + * @param plan [out] A reference to application provided channel plan data + * structure which will be filled in with active channel + * plan. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t get_channel_plan(lorawan_channelplan_t &plan); + + /** + * @brief Remove a given channel from the active plan. + * + * @details Deactivates the given channel. + * + * @param id Id of the channel. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t remove_single_channel(uint8_t id); + + /** + * @brief LoRaMAC multicast channel link service. + * + * @details Links a multicast channel into the linked list. + * + * @param [in] channel_param The multicast channel parameters to link. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t multicast_channel_link(multicast_params_t *channel_param); + + /** + * @brief LoRaMAC multicast channel unlink service. + * + * @details Unlinks a multicast channel from the linked list. + * + * @param [in] channel_param The multicast channel parameters to unlink. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_PARAMETER_INVALID + */ + lorawan_status_t multicast_channel_unlink(multicast_params_t *channel_param); + + /** Binds phy layer to MAC. + * + * @param phy LoRaPHY object + */ + void bind_phy(LoRaPHY &phy); + + /** + * @brief Schedules the frame for sending. + * + * @details Prepares a full MAC frame and schedules it for physical + * transmission. + * + * @param [in] mac_hdr MAC frame header field + * @param [in] fport Payload port + * @param [in] fbuffer MAC frame data buffer to be sent + * @param [in] fbuffer_size MAC frame data buffer size + * + * @return status Status of the operation. LORAWAN_STATUS_OK in case + * of success and a negative error code in case of + * failure. + */ + lorawan_status_t send(loramac_mhdr_t *mac_hdr, const uint8_t fport, + const void *fbuffer, uint16_t fbuffer_size); + + /** + * @brief get_default_tx_datarate Gets the default TX datarate + * @return default TX datarate. + */ + uint8_t get_default_tx_datarate(); + + /** + * @brief enable_adaptive_datarate Enables or disables adaptive datarate. + * @param adr_enabled Flag indicating is adr enabled or disabled. + */ + void enable_adaptive_datarate(bool adr_enabled); + + /** Sets up the data rate. + * + * `set_datarate()` first verifies whether the data rate given is valid or not. + * If it is valid, the system sets the given data rate to the channel. + * + * @param data_rate The intended data rate, for example DR_0 or DR_1. + * Note that the macro DR_* can mean different + * things in different regions. + * + * @return LORAWAN_STATUS_OK if everything goes well, otherwise + * a negative error code. + */ + lorawan_status_t set_channel_data_rate(uint8_t data_rate); + + /** + * @brief tx_ongoing Check whether a prepare is done or not. + * @return True if prepare_ongoing_tx is called, false otherwise. + */ + bool tx_ongoing(); + + /** + * @brief set_tx_ongoing Changes the ongoing status for prepared message. + * @param ongoing The value indicating the status. + */ + void set_tx_ongoing(bool ongoing); + + /** + * @brief reset_ongoing_tx Resets _ongoing_tx_msg. + * @param reset_pending If true resets pending size also. + */ + void reset_ongoing_tx(bool reset_pending = false); + + /** + * @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg. + * @param port The application port number. + * + * @param data A pointer to the data being sent. The ownership of the + * buffer is not transferred. + * + * @param length The size of data in bytes. + * + * @param flags A flag used to determine what type of + * message is being sent. + * + * @param num_retries Number of retries for a confirmed type message + * + * @return The number of bytes prepared for sending. + */ + int16_t prepare_ongoing_tx(const uint8_t port, const uint8_t *data, + uint16_t length, uint8_t flags, uint8_t num_retries); + + /** + * @brief send_ongoing_tx Sends the ongoing_tx_msg + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t send_ongoing_tx(void); + + /** + * @brief device_class Returns active device class + * @return Device class in use. + */ + device_class_t get_device_class() const; + + /** + * @brief set_device_class Sets active device class. + * @param device_class Device class to use. + * @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, + mbed::Callbackrx2_would_be_closure_handler); + + /** + * @brief setup_link_check_request Adds link check request command + * to be put on next outgoing message (when it fits) + */ + void setup_link_check_request(); + + /** + * @brief prepare_join prepares arguments to be ready for join() call. + * @param params Join parameters to use, if NULL, the default will be used. + * @param is_otaa True if joining is to be done using OTAA, false for ABP. + * + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t prepare_join(const lorawan_connect_t *params, bool is_otaa); + + /** + * @brief join Joins the network. + * @param is_otaa True if joining is to be done using OTAA, false for ABP. + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t join(bool is_otaa); + + /** + * MAC operations upon successful transmission + */ + void on_radio_tx_done(lorawan_time_t timestamp); + + /** + * MAC operations upon reception + */ + void on_radio_rx_done(const uint8_t *const payload, uint16_t size, + int16_t rssi, int8_t snr); + + /** + * MAC operations upon transmission timeout + */ + void on_radio_tx_timeout(void); + + /** + * MAC operations upon empty reception slots + * + * @param is_timeout false when radio encountered an error + * true when the an RX slot went empty + * + * @return current RX slot + */ + void on_radio_rx_timeout(bool is_timeout); + + /** + * Handles retransmissions of Join requests if an Accept + * was not received. + * + * @returns true if a retry will be made + */ + bool continue_joining_process(void); + + /** + * Checks if the CONFIRMED data can be sent again or not. + */ + bool continue_sending_process(void); + + /** + * Read-only access to MAC primitive blocks + */ + const loramac_mcps_confirm_t *get_mcps_confirmation() const; + const loramac_mcps_indication_t *get_mcps_indication() const; + const loramac_mlme_confirm_t *get_mlme_confirmation() const; + const loramac_mlme_indication_t *get_mlme_indication() const; + + /** + * Post processing steps in response to actions carried out + * by controller layer and Mac + */ + void post_process_mcps_req(void); + void post_process_mcps_ind(void); + void post_process_mlme_request(void); + void post_process_mlme_ind(void); + + /** + * Set battery level query callback + */ + void set_batterylevel_callback(mbed::Callback battery_level); + + /** + * Returns the event ID of backoff timer. + */ + int get_backoff_timer_event_id(void); + + /** + * Clears out the TX pipe by discarding any outgoing message if the backoff + * timer is still running. + */ + lorawan_status_t clear_tx_pipe(void); + + /** + * Gets the current time + */ + lorawan_time_t get_current_time(void); + + /** + * Gets the current receive slot + */ + 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 + * the stack thread safe. + */ +#if MBED_CONF_RTOS_PRESENT + void lock(void) + { + _mutex.lock(); + } + void unlock(void) + { + _mutex.unlock(); + } +#else + void lock(void) { } + void unlock(void) { } +#endif + +private: + /** + * @brief Queries the LoRaMAC the maximum possible FRMPayload size to send. + * The LoRaMAC takes the scheduled MAC commands into account and returns + * corresponding value. + * + * @param fopts_len [in] Number of mac commands in the queue pending. + * + * @return Size of the biggest packet that can be sent. + * Please note that if the size of the MAC commands in the queue do + * not fit into the payload size on the related datarate, the LoRaMAC will + * omit the MAC commands. + */ + uint8_t get_max_possible_tx_size(uint8_t fopts_len); + + /** + * @brief set_nwk_joined This is used for ABP mode for which real joining does not happen + * @param joined True if device has joined in network, false otherwise + */ + void set_nwk_joined(bool joined); + + /** + * @brief Configures the events to trigger an MLME-Indication with + * a MLME type of MLME_SCHEDULE_UPLINK. + */ + void set_mlme_schedule_ul_indication(void); + + /** + * @brief Resets MAC specific parameters to default + */ + void reset_mac_parameters(void); + + /** + * Handles a Join Accept frame + */ + void handle_join_accept_frame(const uint8_t *payload, uint16_t size); + + /** + * Handles data frames + */ + void handle_data_frame(const uint8_t *payload, uint16_t size, uint8_t ptr_pos, + uint8_t msg_type, int16_t rssi, int8_t snr); + + /** + * Send a Join Request + */ + lorawan_status_t send_join_request(); + + /** + * Handles retransmissions + */ + lorawan_status_t handle_retransmission(); + + /** + * Checks if the frame is valid + */ + void check_frame_size(uint16_t size); + + /** + * Performs MIC + */ + bool message_integrity_check(const uint8_t *payload, uint16_t size, + uint8_t *ptr_pos, uint32_t address, + uint32_t *downlink_counter, const uint8_t *nwk_skey); + + /** + * Decrypts and extracts data and MAC commands from the received encrypted + * payload + */ + void extract_data_and_mac_commands(const uint8_t *payload, uint16_t size, + uint8_t fopts_len, uint8_t *nwk_skey, + uint8_t *app_skey, uint32_t address, + uint32_t downlink_frame_counter, + int16_t rssi, int8_t snr); + /** + * Decrypts and extracts MAC commands from the received encrypted + * payload if there is no data + */ + void extract_mac_commands_only(const uint8_t *payload, int8_t snr, uint8_t fopts_len); + + /** + * Callback function to be executed when the DC backoff timer expires + */ + void on_backoff_timer_expiry(void); + + /** + * At the end of an RX1 window timer, an RX1 window is opened using this method. + */ + void open_rx1_window(void); + + /** + * At the end of an RX2 window timer, an RX2 window is opened using this method. + */ + void open_rx2_window(void); + + /** + * A method to retry a CONFIRMED message after a particular time period + * (ACK_TIMEOUT = TIME_IN_MS) if the ack was not received + */ + void on_ack_timeout_timer_event(void); + + /*! + * \brief Check if the OnAckTimeoutTimer has do be disabled. If so, the + * function disables it. + * + * \param [in] node_ack_requested Set to true, if the node has requested an ACK + * \param [in] dev_class The device class + * \param [in] ack_received Set to true, if the node has received an ACK + * \param [in] ack_timeout_retries_counter Retries counter for confirmed uplinks + * \param [in] ack_timeout_retries Maximum retries for confirmed uplinks + */ + void check_to_disable_ack_timeout(bool node_ack_requested, + device_class_t dev_class, + bool ack_received, + uint8_t ack_timeout_retries_counter, + uint8_t ack_timeout_retries); + + /** + * Validates if the payload fits into the frame, taking the datarate + * into account. + * + * Please Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0.2 + */ + bool validate_payload_length(uint16_t length, int8_t datarate, uint8_t fopts_len); + + /** + * Prepares MAC frame on the behest of send() API. + */ + lorawan_status_t prepare_frame(loramac_mhdr_t *mac_hdr, + loramac_frame_ctrl_t *fctrl, const uint8_t fport, + const void *fbuffer, uint16_t fbuffer_size); + + /** + * Schedules a transmission on the behest of send() API. + */ + lorawan_status_t schedule_tx(); + + /** + * Calculates the back-off time for the band of a channel. + * Takes in the last used channel id as a parameter. + */ + void calculate_backOff(uint8_t channel_id); + + /** + * Hands over the MAC frame to PHY layer. + */ + lorawan_status_t send_frame_on_channel(uint8_t channel); + + /** + * Resets MAC primitive blocks + */ + void reset_mcps_confirmation(void); + void reset_mlme_confirmation(void); + void reset_mcps_indication(void); + + /** + * @brief set_tx_continuous_wave Puts the system in continuous transmission mode + * @param [in] channel A Channel to use + * @param [in] datarate A datarate to use + * @param [in] tx_power A RF output power to use + * @param [in] max_eirp A maximum possible EIRP to use + * @param [in] antenna_gain Antenna gain to use + * @param [in] timeout Time in seconds while the radio is kept in continuous wave mode + */ + void set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, + float max_eirp, float antenna_gain, uint16_t timeout); + +private: + typedef mbed::ScopedLock Lock; +#if MBED_CONF_RTOS_PRESENT + rtos::Mutex _mutex; +#endif + + /** + * Timer subsystem handle + */ + LoRaWANTimeHandler _lora_time; + + /** + * LoRa PHY layer object storage + */ + LoRaPHY *_lora_phy; + + /** + * MAC command handle + */ + LoRaMacCommand _mac_commands; + + /** + * Channel planning subsystem + */ + LoRaMacChannelPlan _channel_plan; + + /** + * Crypto handling subsystem + */ + LoRaMacCrypto _lora_crypto; + + /** + * Central MAC layer data storage + */ + loramac_protocol_params _params; + + /** + * EventQueue object storage + */ + events::EventQueue *_ev_queue; + + /** + * Class C doesn't timeout in RX2 window as it is a continuous window. + * We use this callback to inform the LoRaWANStack controller that we did + * 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 _rx2_would_be_closure_for_class_c; + + /** + * Transmission is async, i.e., a call to schedule_tx() may be deferred to + * a time after a certain back off. We use this callback to inform the + * controller layer that a specific TX transaction failed to schedule after + * backoff or retry. + */ + mbed::Callback _scheduling_failure_handler; + + timer_event_t _rx2_closure_timer_for_class_c; + + /** + * Structure to hold MCPS indication data. + */ + loramac_mcps_indication_t _mcps_indication; + + /** + * Structure to hold MCPS confirm data. + */ + loramac_mcps_confirm_t _mcps_confirmation; + + /** + * Structure to hold MLME indication data. + */ + loramac_mlme_indication_t _mlme_indication; + + /** + * Structure to hold MLME confirm data. + */ + loramac_mlme_confirm_t _mlme_confirmation; + + loramac_tx_message_t _ongoing_tx_msg; + + bool _is_nwk_joined; + + bool _can_cancel_tx; + + bool _continuous_rx2_window_open; + + device_class_t _device_class; + + uint8_t _prev_qos_level; + + bool _demod_ongoing; +}; + +#endif // MBED_LORAWAN_MAC_H__ diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp b/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp new file mode 100644 index 0000000..a19bdf7 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp @@ -0,0 +1,170 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRaWAN stack layer that controls both MAC and PHY underneath + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "LoRaMacChannelPlan.h" + +LoRaMacChannelPlan::LoRaMacChannelPlan() : _lora_phy(NULL) +{ +} + +LoRaMacChannelPlan::~LoRaMacChannelPlan() +{ +} + +void LoRaMacChannelPlan::activate_channelplan_subsystem(LoRaPHY *phy) +{ + _lora_phy = phy; +} + +lorawan_status_t LoRaMacChannelPlan::set_plan(const lorawan_channelplan_t &plan) +{ + lorawan_status_t status; + + uint8_t max_num_channels; + + if (!_lora_phy->is_custom_channel_plan_supported()) { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + max_num_channels = _lora_phy->get_max_nb_channels(); + + // check if user is setting more channels than supported + if (plan.nb_channels > max_num_channels) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + for (uint8_t i = 0; i < plan.nb_channels; i++) { + status = _lora_phy->add_channel(&plan.channels[i].ch_param, plan.channels[i].id); + + if (status != LORAWAN_STATUS_OK) { + return status; + } + } + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMacChannelPlan::get_plan(lorawan_channelplan_t &plan, + const channel_params_t *channel_list) +{ + uint8_t max_num_channels; + uint16_t *channel_mask; + uint8_t count = 0; + + if (!_lora_phy->is_custom_channel_plan_supported()) { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + max_num_channels = _lora_phy->get_max_nb_channels(); + + channel_mask = _lora_phy->get_channel_mask(false); + + for (uint8_t i = 0; i < max_num_channels; i++) { + // skip the channels which are not enabled + if (_lora_phy->mask_bit_test(channel_mask, i) == 0) { + continue; + } + + // otherwise add them to the channel_plan struct + plan.channels[count].id = i; + plan.channels[count].ch_param.frequency = channel_list[i].frequency; + plan.channels[count].ch_param.dr_range.value = channel_list[i].dr_range.value; + plan.channels[count].ch_param.dr_range.fields.min = channel_list[i].dr_range.fields.min; + plan.channels[count].ch_param.dr_range.fields.max = channel_list[i].dr_range.fields.max; + plan.channels[count].ch_param.band = channel_list[i].band; + plan.channels[count].ch_param.rx1_frequency = channel_list[i].rx1_frequency; + count++; + } + + plan.nb_channels = count; + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMacChannelPlan::remove_plan() +{ + lorawan_status_t status = LORAWAN_STATUS_OK; + + uint8_t max_num_channels; + uint16_t *channel_mask; + uint16_t *default_channel_mask; + + if (!_lora_phy->is_custom_channel_plan_supported()) { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + max_num_channels = _lora_phy->get_max_nb_channels(); + + channel_mask = _lora_phy->get_channel_mask(false); + + default_channel_mask = _lora_phy->get_channel_mask(true); + + for (uint8_t i = 0; i < max_num_channels; i++) { + // skip any default channels + if (_lora_phy->mask_bit_test(default_channel_mask, i) != 0) { + continue; + } + + // skip any channels which are not currently enabled + if (_lora_phy->mask_bit_test(channel_mask, i) == 0) { + continue; + } + + status = remove_single_channel(i); + + if (status != LORAWAN_STATUS_OK) { + return status; + } + } + + return status; +} + +lorawan_status_t LoRaMacChannelPlan::remove_single_channel(uint8_t channel_id) +{ + uint8_t max_num_channels; + + if (!_lora_phy->is_custom_channel_plan_supported()) { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + max_num_channels = _lora_phy->get_max_nb_channels(); + + // According to specification channel IDs start from 0 and last valid + // channel ID is N-1 where N=MAX_NUM_CHANNELS. + // So any ID which is larger or equal to the Max number of channels is invalid + if (channel_id >= max_num_channels) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + if (_lora_phy->remove_channel(channel_id) == false) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + _lora_phy->put_radio_to_sleep(); + + return LORAWAN_STATUS_OK; +} + diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.h b/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.h new file mode 100644 index 0000000..6fd3a44 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacChannelPlan.h @@ -0,0 +1,114 @@ +/** + \code + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== +\endcode + +Description: LoRaWAN stack layer that controls both MAC and PHY underneath + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef MBED_LORAWAN_LORAMACCHANNELPLAN_H_ +#define MBED_LORAWAN_LORAMACCHANNELPLAN_H_ + +#include "system/lorawan_data_structures.h" +#include "lorastack/phy/LoRaPHY.h" + +class LoRaMacChannelPlan { + +public: + + /** Constructor + * + * Sets local handles to NULL. These handles will be set when the subsystem + * is activated by the MAC layer. + */ + LoRaMacChannelPlan(); + + /** Destructor + * + * Does nothing + */ + ~LoRaMacChannelPlan(); + + /** Activates Channel Planning subsystem + * + * Stores pointers to PHY layer MIB subsystem + * + * @param phy pointer to PHY layer + */ + void activate_channelplan_subsystem(LoRaPHY *phy); + + /** Set a given channel plan + * + * Used to set application provided channel plan. This API can be used to + * set a single channel as well to the existing channel plan. + * + * @param plan a reference to application channel plan. PHY layer takes a + * copy of the channel parameters provided within. + * + * @return LORAWAN_STATUS_OK if everything goes well otherwise + * a negative error code is returned. + */ + lorawan_status_t set_plan(const lorawan_channelplan_t &plan); + + /** Access the active channel plan + * + * Used to get active channel plan. + * + * @param plan a reference to application provided channel plan structure + * which gets filled in with active channel plan data. + * + * @param channel_list pointer to structure containing channel information + * + * @return LORAWAN_STATUS_OK if everything goes well otherwise + * a negative error code is returned. + */ + lorawan_status_t get_plan(lorawan_channelplan_t &plan, const channel_params_t *channel_list); + + /** Remove the active channel plan + * + * Drops the whole channel list except the 'Default Channels' ofcourse. + * + * @return LORAWAN_STATUS_OK if everything goes well otherwise + * a negative error code is returned. + */ + lorawan_status_t remove_plan(); + + /** Remove a single channel from the plan + * + * @param id the channel id which needs to be removed + * + * @return LORAWAN_STATUS_OK if everything goes well otherwise + * a negative error code is returned. + */ + lorawan_status_t remove_single_channel(uint8_t id); + +private: + + /** + * Local handles + */ + LoRaPHY *_lora_phy; +}; + + + +#endif /* MBED_LORAWAN_LORAMACCHANNELPLAN_H_ */ diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacCommand.cpp b/connectivity/lorawan/lorastack/mac/LoRaMacCommand.cpp new file mode 100644 index 0000000..0438655 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacCommand.cpp @@ -0,0 +1,424 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRa MAC layer implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include +#include "LoRaMacCommand.h" +#include "LoRaMac.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "LMACC" + +/** + * LoRaMAC max EIRP (dBm) table. + */ +static const uint8_t max_eirp_table[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; + +LoRaMacCommand::LoRaMacCommand() +{ + sticky_mac_cmd = false; + mac_cmd_buf_idx = 0; + mac_cmd_buf_idx_to_repeat = 0; + + memset(mac_cmd_buffer, 0, sizeof(mac_cmd_buffer)); + memset(mac_cmd_buffer_to_repeat, 0, sizeof(mac_cmd_buffer_to_repeat)); +} + +void LoRaMacCommand::clear_command_buffer() +{ + mac_cmd_buf_idx = 0; +} + +uint8_t LoRaMacCommand::get_mac_cmd_length() const +{ + return mac_cmd_buf_idx; +} + +uint8_t *LoRaMacCommand::get_mac_commands_buffer() +{ + return mac_cmd_buffer; +} + +void LoRaMacCommand::parse_mac_commands_to_repeat() +{ + uint8_t i = 0; + uint8_t cmd_cnt = 0; + + for (i = 0; i < mac_cmd_buf_idx; i++) { + switch (mac_cmd_buffer[i]) { + // STICKY + case MOTE_MAC_DL_CHANNEL_ANS: + case MOTE_MAC_RX_PARAM_SETUP_ANS: { // 1 byte payload + mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i++]; + mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; + break; + } + case MOTE_MAC_RX_TIMING_SETUP_ANS: { // 0 byte payload + mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; + break; + } + + // NON-STICKY + case MOTE_MAC_DEV_STATUS_ANS: { // 2 bytes payload + i += 2; + break; + } + case MOTE_MAC_LINK_ADR_ANS: + case MOTE_MAC_NEW_CHANNEL_ANS: { // 1 byte payload + i++; + break; + } + case MOTE_MAC_TX_PARAM_SETUP_ANS: + case MOTE_MAC_DUTY_CYCLE_ANS: + case MOTE_MAC_LINK_CHECK_REQ: { // 0 byte payload + break; + } + default: { + MBED_ASSERT(false); + } + } + } + + mac_cmd_buf_idx_to_repeat = cmd_cnt; +} + +void LoRaMacCommand::clear_repeat_buffer() +{ + mac_cmd_buf_idx_to_repeat = 0; +} + +void LoRaMacCommand::copy_repeat_commands_to_buffer() +{ + memcpy(&mac_cmd_buffer[mac_cmd_buf_idx], mac_cmd_buffer_to_repeat, mac_cmd_buf_idx_to_repeat); + mac_cmd_buf_idx += mac_cmd_buf_idx_to_repeat; +} + +uint8_t LoRaMacCommand::get_repeat_commands_length() const +{ + return mac_cmd_buf_idx_to_repeat; +} + +void LoRaMacCommand::clear_sticky_mac_cmd() +{ + sticky_mac_cmd = false; +} + +bool LoRaMacCommand::has_sticky_mac_cmd() const +{ + return sticky_mac_cmd; +} + +lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index, + uint8_t commands_size, uint8_t snr, + loramac_mlme_confirm_t &mlme_conf, + lora_mac_system_params_t &mac_sys_params, + LoRaPHY &lora_phy) +{ + uint8_t status = 0; + lorawan_status_t ret_value = LORAWAN_STATUS_OK; + + while (mac_index < commands_size) { + // Decode Frame MAC commands + switch (payload[mac_index++]) { + case SRV_MAC_LINK_CHECK_ANS: + mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK; + mlme_conf.demod_margin = payload[mac_index++]; + mlme_conf.nb_gateways = payload[mac_index++]; + break; + case SRV_MAC_LINK_ADR_REQ: { + adr_req_params_t link_adr_req; + int8_t link_adr_dr = DR_0; + int8_t link_adr_txpower = TX_POWER_0; + uint8_t link_adr_nbtrans = 0; + uint8_t link_adr_nb_bytes_parsed = 0; + + // Fill parameter structure + link_adr_req.payload = &payload[mac_index - 1]; + link_adr_req.payload_size = commands_size - (mac_index - 1); + link_adr_req.adr_enabled = mac_sys_params.adr_on; + link_adr_req.ul_dwell_time = mac_sys_params.uplink_dwell_time; + link_adr_req.current_datarate = mac_sys_params.channel_data_rate; + link_adr_req.current_tx_power = mac_sys_params.channel_tx_power; + link_adr_req.current_nb_trans = mac_sys_params.nb_trans; + + // Process the ADR requests + status = lora_phy.link_ADR_request(&link_adr_req, + &link_adr_dr, + &link_adr_txpower, + &link_adr_nbtrans, + &link_adr_nb_bytes_parsed); + + // If nothing was consumed, we have a malformed packet at our hand + // we bin everything and return. link_adr_nb_bytes_parsed being 0 is + // a magic identifier letting us know that there are payload inconsistencies + if (link_adr_nb_bytes_parsed == 0) { + return LORAWAN_STATUS_UNSUPPORTED; + } + + if ((status & 0x07) == 0x07) { + mac_sys_params.channel_data_rate = link_adr_dr; + mac_sys_params.channel_tx_power = link_adr_txpower; + mac_sys_params.nb_trans = link_adr_nbtrans; + } + + // Add the answers to the buffer + for (uint8_t i = 0; i < (link_adr_nb_bytes_parsed / 5); i++) { + ret_value = add_link_adr_ans(status); + } + // Update MAC index + mac_index += link_adr_nb_bytes_parsed - 1; + } + break; + case SRV_MAC_DUTY_CYCLE_REQ: + mac_sys_params.max_duty_cycle = payload[mac_index++]; + mac_sys_params.aggregated_duty_cycle = 1 << mac_sys_params.max_duty_cycle; + ret_value = add_duty_cycle_ans(); + break; + case SRV_MAC_RX_PARAM_SETUP_REQ: { + rx_param_setup_req_t rxParamSetupReq; + + rxParamSetupReq.dr_offset = (payload[mac_index] >> 4) & 0x07; + rxParamSetupReq.datarate = payload[mac_index++] & 0x0F; + + rxParamSetupReq.frequency = (uint32_t) payload[mac_index++]; + rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 8; + rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 16; + rxParamSetupReq.frequency *= 100; + + // Perform request on region + status = lora_phy.accept_rx_param_setup_req(&rxParamSetupReq); + + if ((status & 0x07) == 0x07) { + mac_sys_params.rx2_channel.datarate = rxParamSetupReq.datarate; + mac_sys_params.rx2_channel.frequency = rxParamSetupReq.frequency; + mac_sys_params.rx1_dr_offset = rxParamSetupReq.dr_offset; + } + ret_value = add_rx_param_setup_ans(status); + } + break; + case SRV_MAC_DEV_STATUS_REQ: { + uint8_t battery_level = BAT_LEVEL_NO_MEASURE; + if (_battery_level_cb) { + battery_level = _battery_level_cb(); + } + ret_value = add_dev_status_ans(battery_level, snr & 0x3F); + break; + } + case SRV_MAC_NEW_CHANNEL_REQ: { + channel_params_t chParam; + int8_t channel_id = payload[mac_index++]; + + chParam.frequency = (uint32_t) payload[mac_index++]; + chParam.frequency |= (uint32_t) payload[mac_index++] << 8; + chParam.frequency |= (uint32_t) payload[mac_index++] << 16; + chParam.frequency *= 100; + chParam.rx1_frequency = 0; + chParam.dr_range.value = payload[mac_index++]; + + status = lora_phy.request_new_channel(channel_id, &chParam); + + ret_value = add_new_channel_ans(status); + } + break; + case SRV_MAC_RX_TIMING_SETUP_REQ: { + uint8_t delay = payload[mac_index++] & 0x0F; + + if (delay == 0) { + delay++; + } + mac_sys_params.recv_delay1 = delay * 1000; + mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; + ret_value = add_rx_timing_setup_ans(); + } + break; + case SRV_MAC_TX_PARAM_SETUP_REQ: { + uint8_t eirpDwellTime = payload[mac_index++]; + uint8_t ul_dwell_time; + uint8_t dl_dwell_time; + uint8_t max_eirp; + + ul_dwell_time = 0; + dl_dwell_time = 0; + + if ((eirpDwellTime & 0x20) == 0x20) { + dl_dwell_time = 1; + } + if ((eirpDwellTime & 0x10) == 0x10) { + ul_dwell_time = 1; + } + max_eirp = eirpDwellTime & 0x0F; + + // Check the status for correctness + if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { + // Accept command + mac_sys_params.uplink_dwell_time = ul_dwell_time; + mac_sys_params.downlink_dwell_time = dl_dwell_time; + mac_sys_params.max_eirp = max_eirp_table[max_eirp]; + // Add command response + ret_value = add_tx_param_setup_ans(); + } + } + break; + case SRV_MAC_DL_CHANNEL_REQ: { + uint8_t channel_id = payload[mac_index++]; + uint32_t rx1_frequency; + + rx1_frequency = (uint32_t) payload[mac_index++]; + rx1_frequency |= (uint32_t) payload[mac_index++] << 8; + rx1_frequency |= (uint32_t) payload[mac_index++] << 16; + rx1_frequency *= 100; + status = lora_phy.dl_channel_request(channel_id, rx1_frequency); + + ret_value = add_dl_channel_ans(status); + } + break; + default: + // Unknown command. ABORT MAC commands processing + tr_error("Invalid MAC command (0x%X)!", payload[mac_index]); + return LORAWAN_STATUS_UNSUPPORTED; + } + } + return ret_value; +} + +int32_t LoRaMacCommand::cmd_buffer_remaining() const +{ + // The maximum buffer length must take MAC commands to re-send into account. + return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; +} + +void LoRaMacCommand::set_batterylevel_callback(mbed::Callback battery_level) +{ + _battery_level_cb = battery_level; +} + +lorawan_status_t LoRaMacCommand::add_link_check_req() +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 0) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_CHECK_REQ; + // No payload for this command + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status) +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 1) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_ADR_ANS; + mac_cmd_buffer[mac_cmd_buf_idx++] = status; + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_duty_cycle_ans() +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 0) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DUTY_CYCLE_ANS; + // No payload for this answer + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_rx_param_setup_ans(uint8_t status) +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 1) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_PARAM_SETUP_ANS; + // Status: Datarate ACK, Channel ACK + mac_cmd_buffer[mac_cmd_buf_idx++] = status; + // This is a sticky MAC command answer. Setup indication + sticky_mac_cmd = true; + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_dev_status_ans(uint8_t battery, uint8_t margin) +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 2) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEV_STATUS_ANS; + // 1st byte Battery + // 2nd byte Margin + mac_cmd_buffer[mac_cmd_buf_idx++] = battery; + mac_cmd_buffer[mac_cmd_buf_idx++] = margin; + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_new_channel_ans(uint8_t status) +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 1) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_NEW_CHANNEL_ANS; + // Status: Datarate range OK, Channel frequency OK + mac_cmd_buffer[mac_cmd_buf_idx++] = status; + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_rx_timing_setup_ans() +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 0) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_TIMING_SETUP_ANS; + // No payload for this answer + // This is a sticky MAC command answer. Setup indication + sticky_mac_cmd = true; + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_tx_param_setup_ans() +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 0) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_TX_PARAM_SETUP_ANS; + // No payload for this answer + ret = LORAWAN_STATUS_OK; + } + return ret; +} + +lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status) +{ + lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; + if (cmd_buffer_remaining() > 1) { + mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DL_CHANNEL_ANS; + // Status: Uplink frequency exists, Channel frequency OK + mac_cmd_buffer[mac_cmd_buf_idx++] = status; + // This is a sticky MAC command answer. Setup indication + sticky_mac_cmd = true; + ret = LORAWAN_STATUS_OK; + } + return ret; +} diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacCommand.h b/connectivity/lorawan/lorastack/mac/LoRaMacCommand.h new file mode 100644 index 0000000..93f285e --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacCommand.h @@ -0,0 +1,253 @@ +/** + * \file LoRaMacCommand.h + * + * \brief LoRa MAC layer implementation + * + * \copyright Revised BSD License, see LICENSE.TXT file include in the project + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) + * + * \defgroup LORAMAC LoRa MAC layer implementation + * This module specifies the API implementation of the LoRaMAC layer. + * This is a placeholder for a detailed description of the LoRaMac + * layer and the supported features. + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __LORAMACCOMMAND_H__ +#define __LORAMACCOMMAND_H__ + +#include +#include "system/lorawan_data_structures.h" +#include "lorastack/phy/LoRaPHY.h" + +/*! + * Maximum MAC commands buffer size + */ +#define LORA_MAC_COMMAND_MAX_LENGTH 128 + +class LoRaMac; + +/** LoRaMacCommand Class + * Helper class for LoRaMac layer to handle any MAC commands + */ +class LoRaMacCommand { + +public: + LoRaMacCommand(); + + /** + * @brief Clear MAC command buffer. + */ + void clear_command_buffer(void); + + /** + * @brief Get the length of MAC commands + * + * @return status Length of used MAC buffer (bytes) + */ + uint8_t get_mac_cmd_length() const; + + /** + * @brief Get MAC command buffer + * + * @return Pointer to MAC command buffer + */ + uint8_t *get_mac_commands_buffer(); + + /** + * @brief Parses the MAC commands which must be re-sent. + */ + void parse_mac_commands_to_repeat(); + + /** + * @brief Clear MAC command repeat buffer. + */ + void clear_repeat_buffer(); + + /** + * @brief Copy MAC commands from repeat buffer to actual MAC command buffer. + */ + void copy_repeat_commands_to_buffer(); + + /** + * @brief Get the length of MAC commands in repeat buffer + * + * @return status Length of used MAC Repeat buffer (bytes) + */ + uint8_t get_repeat_commands_length() const; + + /** + * @brief Clear sticky MAC commands. + */ + void clear_sticky_mac_cmd(); + + /** + * @brief Check if MAC command buffer contains sticky commands + * + * @return status True: buffer has sticky MAC commands in it, false: no sticky commands in buffer + */ + bool has_sticky_mac_cmd() const; + + /** + * @brief Decodes MAC commands in the fOpts field and in the payload + * + * @return status Function status. LORAWAN_STATUS_OK if command successful. + */ + lorawan_status_t process_mac_commands(const uint8_t *payload, uint8_t mac_index, + uint8_t commands_size, uint8_t snr, + loramac_mlme_confirm_t &mlme_conf, + lora_mac_system_params_t &mac_params, + LoRaPHY &lora_phy); + + /** + * @brief Adds a new LinkCheckReq MAC command to be sent. + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_link_check_req(); + + /** + * @brief Set battery level query callback method + * If callback is not set, BAT_LEVEL_NO_MEASURE is returned. + */ + void set_batterylevel_callback(mbed::Callback battery_level); + +private: + /** + * @brief Get the remaining size of the MAC command buffer + * + * @return Remaining free space in buffer (bytes). + */ + int32_t cmd_buffer_remaining() const; + + /** + * @brief Adds a new LinkAdrAns MAC command to be sent. + * + * @param [in] status Status bits + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_link_adr_ans(uint8_t status); + + /** + * @brief Adds a new DutyCycleAns MAC command to be sent. + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_duty_cycle_ans(); + + /** + * @brief Adds a new RXParamSetupAns MAC command to be sent. + * + * @param [in] status Status bits + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_rx_param_setup_ans(uint8_t status); + + /** + * @brief Adds a new DevStatusAns MAC command to be sent. + * + * @param [in] battery Battery level + * @param [in] margin Demodulation signal-to-noise ratio (dB) + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_dev_status_ans(uint8_t battery, uint8_t margin); + + /** + * @brief Adds a new NewChannelAns MAC command to be sent. + * + * @param [in] status Status bits + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_new_channel_ans(uint8_t status); + + /** + * @brief Adds a new RXTimingSetupAns MAC command to be sent. + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_rx_timing_setup_ans(); + + /** + * @brief Adds a new TXParamSetupAns MAC command to be sent. + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_tx_param_setup_ans(); + + /** + * @brief Adds a new DlChannelAns MAC command to be sent. + * + * @param [in] status Status bits + * + * @return status Function status: LORAWAN_STATUS_OK: OK, + * LORAWAN_STATUS_LENGTH_ERROR: Buffer full + */ + lorawan_status_t add_dl_channel_ans(uint8_t status); + +private: + /** + * Indicates if there are any pending sticky MAC commands + */ + bool sticky_mac_cmd; + + /** + * Contains the current Mac command buffer index in 'mac_cmd_buffer' + */ + uint8_t mac_cmd_buf_idx; + + /** + * Contains the current Mac command buffer index for MAC commands to repeat in + * 'mac_cmd_buffer_to_repeat' + */ + uint8_t mac_cmd_buf_idx_to_repeat; + + /** + * Buffer containing the MAC layer commands + */ + uint8_t mac_cmd_buffer[LORA_MAC_COMMAND_MAX_LENGTH]; + + /** + * Buffer containing the MAC layer commands which must be repeated + */ + uint8_t mac_cmd_buffer_to_repeat[LORA_MAC_COMMAND_MAX_LENGTH]; + + mbed::Callback _battery_level_cb; +}; + +#endif //__LORAMACCOMMAND_H__ diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.cpp b/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.cpp new file mode 100644 index 0000000..cb0a419 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.cpp @@ -0,0 +1,369 @@ +/** + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * Description: LoRa MAC crypto implementation + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) + * + * + * Copyright (c) 2017, Arm Limited and affiliates. + * + * SPDX-License-Identifier: BSD-3-Clause +*/ + +#include +#include +#include + +#include "LoRaMacCrypto.h" +#include "system/lorawan_data_structures.h" +#include "mbedtls/platform.h" + + +#if defined(MBEDTLS_CMAC_C) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_CIPHER_C) + +LoRaMacCrypto::LoRaMacCrypto() +{ +#if defined(MBEDTLS_PLATFORM_C) + int ret = mbedtls_platform_setup(NULL); + if (ret != 0) { + MBED_ASSERT(0 && "LoRaMacCrypto: Fail in mbedtls_platform_setup."); + } +#endif /* MBEDTLS_PLATFORM_C */ +} + +LoRaMacCrypto::~LoRaMacCrypto() +{ +#if defined(MBEDTLS_PLATFORM_C) + mbedtls_platform_teardown(NULL); +#endif /* MBEDTLS_PLATFORM_C */ +} + +int LoRaMacCrypto::compute_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, const uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint32_t *mic) +{ + uint8_t computed_mic[16] = {}; + uint8_t mic_block_b0[16] = {}; + int ret = 0; + + mic_block_b0[0] = 0x49; + + mic_block_b0[5] = dir; + + mic_block_b0[6] = (address) & 0xFF; + mic_block_b0[7] = (address >> 8) & 0xFF; + mic_block_b0[8] = (address >> 16) & 0xFF; + mic_block_b0[9] = (address >> 24) & 0xFF; + + mic_block_b0[10] = (seq_counter) & 0xFF; + mic_block_b0[11] = (seq_counter >> 8) & 0xFF; + mic_block_b0[12] = (seq_counter >> 16) & 0xFF; + mic_block_b0[13] = (seq_counter >> 24) & 0xFF; + + mic_block_b0[15] = size & 0xFF; + + mbedtls_cipher_init(aes_cmac_ctx); + + const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + + if (NULL != cipher_info) { + ret = mbedtls_cipher_setup(aes_cmac_ctx, cipher_info); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, mic_block_b0, sizeof(mic_block_b0)); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, buffer, size & 0xFF); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_finish(aes_cmac_ctx, computed_mic); + if (0 != ret) { + goto exit; + } + + *mic = (uint32_t)((uint32_t) computed_mic[3] << 24 + | (uint32_t) computed_mic[2] << 16 + | (uint32_t) computed_mic[1] << 8 | (uint32_t) computed_mic[0]); + } else { + ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED; + } + +exit: + mbedtls_cipher_free(aes_cmac_ctx); + return ret; +} + +int LoRaMacCrypto::encrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, const uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *enc_buffer) +{ + uint16_t i; + uint8_t bufferIndex = 0; + uint16_t ctr = 1; + int ret = 0; + uint8_t a_block[16] = {}; + uint8_t s_block[16] = {}; + + mbedtls_aes_init(&aes_ctx); + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); + if (0 != ret) { + goto exit; + } + + a_block[0] = 0x01; + a_block[5] = dir; + + a_block[6] = (address) & 0xFF; + a_block[7] = (address >> 8) & 0xFF; + a_block[8] = (address >> 16) & 0xFF; + a_block[9] = (address >> 24) & 0xFF; + + a_block[10] = (seq_counter) & 0xFF; + a_block[11] = (seq_counter >> 8) & 0xFF; + a_block[12] = (seq_counter >> 16) & 0xFF; + a_block[13] = (seq_counter >> 24) & 0xFF; + + while (size >= 16) { + a_block[15] = ((ctr) & 0xFF); + ctr++; + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, a_block, + s_block); + if (0 != ret) { + goto exit; + } + + for (i = 0; i < 16; i++) { + enc_buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ s_block[i]; + } + size -= 16; + bufferIndex += 16; + } + + if (size > 0) { + a_block[15] = ((ctr) & 0xFF); + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, a_block, + s_block); + if (0 != ret) { + goto exit; + } + + for (i = 0; i < size; i++) { + enc_buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ s_block[i]; + } + } + +exit: + mbedtls_aes_free(&aes_ctx); + return ret; +} + +int LoRaMacCrypto::decrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *dec_buffer) +{ + return encrypt_payload(buffer, size, key, key_length, address, dir, seq_counter, + dec_buffer); +} + +int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t *mic) +{ + uint8_t computed_mic[16] = {}; + int ret = 0; + + mbedtls_cipher_init(aes_cmac_ctx); + const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + + if (NULL != cipher_info) { + ret = mbedtls_cipher_setup(aes_cmac_ctx, cipher_info); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, buffer, size & 0xFF); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_cipher_cmac_finish(aes_cmac_ctx, computed_mic); + if (0 != ret) { + goto exit; + } + + *mic = (uint32_t)((uint32_t) computed_mic[3] << 24 + | (uint32_t) computed_mic[2] << 16 + | (uint32_t) computed_mic[1] << 8 | (uint32_t) computed_mic[0]); + } else { + ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED; + } + +exit: + mbedtls_cipher_free(aes_cmac_ctx); + return ret; +} + +int LoRaMacCrypto::decrypt_join_frame(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint8_t *dec_buffer) +{ + int ret = 0; + + mbedtls_aes_init(&aes_ctx); + + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); + if (0 != ret) { + goto exit; + } + + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, buffer, + dec_buffer); + if (0 != ret) { + goto exit; + } + + // Check if optional CFList is included + if (size >= 16) { + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, buffer + 16, + dec_buffer + 16); + } + +exit: + mbedtls_aes_free(&aes_ctx); + return ret; +} + +int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, + const uint8_t *app_nonce, uint16_t dev_nonce, + uint8_t *nwk_skey, uint8_t *app_skey) +{ + uint8_t nonce[16]; + uint8_t *p_dev_nonce = (uint8_t *) &dev_nonce; + int ret = 0; + + mbedtls_aes_init(&aes_ctx); + + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); + if (0 != ret) { + goto exit; + } + + memset(nonce, 0, sizeof(nonce)); + nonce[0] = 0x01; + memcpy(nonce + 1, app_nonce, 6); + memcpy(nonce + 7, p_dev_nonce, 2); + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, nwk_skey); + if (0 != ret) { + goto exit; + } + + memset(nonce, 0, sizeof(nonce)); + nonce[0] = 0x02; + memcpy(nonce + 1, app_nonce, 6); + memcpy(nonce + 7, p_dev_nonce, 2); + ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, app_skey); + +exit: + mbedtls_aes_free(&aes_ctx); + return ret; +} +#else + +LoRaMacCrypto::LoRaMacCrypto() +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); +} + +LoRaMacCrypto::~LoRaMacCrypto() +{ +} + +// If mbedTLS is not configured properly, these dummies will ensure that +// user knows what is wrong and in addition to that these ensure that +// Mbed-OS compiles properly under normal conditions where LoRaWAN in conjunction +// with mbedTLS is not being used. +int LoRaMacCrypto::compute_mic(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, + uint8_t dir, uint32_t, uint32_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +int LoRaMacCrypto::encrypt_payload(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, + uint8_t, uint32_t, uint8_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +int LoRaMacCrypto::decrypt_payload(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, + uint8_t, uint32_t, uint8_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +int LoRaMacCrypto::decrypt_join_frame(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint8_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *, uint32_t, const uint8_t *, uint16_t, + uint8_t *, uint8_t *) +{ + MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); + + // Never actually reaches here + return LORAWAN_STATUS_CRYPTO_FAIL; +} + +#endif diff --git a/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.h b/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.h new file mode 100644 index 0000000..7117367 --- /dev/null +++ b/connectivity/lorawan/lorastack/mac/LoRaMacCrypto.h @@ -0,0 +1,165 @@ +/** +\code + + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +\endcode + +Description: LoRa MAC Crypto implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ +#define MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ + +#include "mbedtls/aes.h" +#include "mbedtls/cmac.h" + + +class LoRaMacCrypto { +public: + /** + * Constructor + */ + LoRaMacCrypto(); + + /** + * Destructor + */ + ~LoRaMacCrypto(); + + /** + * Computes the LoRaMAC frame MIC field + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] mic - Computed MIC field + * + * @return 0 if successful, or a cipher specific error code + */ + int compute_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint32_t *mic); + + /** + * Performs payload encryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] enc_buffer - Encrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int encrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *enc_buffer); + + /** + * Performs payload decryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] dec_buffer - Decrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int decrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *dec_buffer); + + /** + * Computes the LoRaMAC Join Request frame MIC field + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [out] mic - Computed MIC field + * + * @return 0 if successful, or a cipher specific error code + * + */ + int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t *mic); + + /** + * Computes the LoRaMAC join frame decryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [out] dec_buffer - Decrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int decrypt_join_frame(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint8_t *dec_buffer); + + /** + * Computes the LoRaMAC join frame decryption + * + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] app_nonce - Application nonce + * @param [in] dev_nonce - Device nonce + * @param [out] nwk_skey - Network session key + * @param [out] app_skey - Application session key + * + * @return 0 if successful, or a cipher specific error code + */ + int compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, + const uint8_t *app_nonce, uint16_t dev_nonce, + uint8_t *nwk_skey, uint8_t *app_skey); + +private: + /** + * AES computation context variable + */ + mbedtls_aes_context aes_ctx; + + /** + * CMAC computation context variable + */ + mbedtls_cipher_context_t aes_cmac_ctx[1]; +}; + +#endif // MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHY.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHY.cpp new file mode 100644 index 0000000..3161e65 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHY.cpp @@ -0,0 +1,1464 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include +#include +#include +#include +#include + +#include "LoRaPHY.h" + +#define BACKOFF_DC_1_HOUR 100 +#define BACKOFF_DC_10_HOURS 1000 +#define BACKOFF_DC_24_HOURS 10000 +#define MAX_PREAMBLE_LENGTH 8.0f +#define TICK_GRANULARITY_JITTER 1.0f +#define CHANNELS_IN_MASK 16 + +LoRaPHY::LoRaPHY() + : _radio(NULL), + _lora_time(NULL) +{ + memset(&phy_params, 0, sizeof(phy_params)); +} + +LoRaPHY::~LoRaPHY() +{ + _radio = NULL; +} + +void LoRaPHY::initialize(LoRaWANTimeHandler *lora_time) +{ + _lora_time = lora_time; +} + +bool LoRaPHY::mask_bit_test(const uint16_t *mask, unsigned bit) +{ + return mask[bit / 16] & (1U << (bit % 16)); +} + +void LoRaPHY::mask_bit_set(uint16_t *mask, unsigned bit) +{ + mask[bit / 16] |= (1U << (bit % 16)); +} + +void LoRaPHY::mask_bit_clear(uint16_t *mask, unsigned bit) +{ + mask[bit / 16] &= ~(1U << (bit % 16)); +} + +void LoRaPHY::set_radio_instance(LoRaRadio &radio) +{ + _radio = &radio; +} + +void LoRaPHY::put_radio_to_sleep() +{ + _radio->lock(); + _radio->sleep(); + _radio->unlock(); +} + +void LoRaPHY::put_radio_to_standby() +{ + _radio->lock(); + _radio->standby(); + _radio->unlock(); +} + +void LoRaPHY::setup_public_network_mode(bool set) +{ + _radio->lock(); + _radio->set_public_network(set); + _radio->unlock(); +} + +void LoRaPHY::handle_receive(void) +{ + _radio->lock(); + _radio->receive(); + _radio->unlock(); +} + +// For DevNonce for example +uint32_t LoRaPHY::get_radio_rng() +{ + uint32_t rand; + + _radio->lock(); + rand = _radio->random(); + _radio->unlock(); + + return rand; +} + +void LoRaPHY::handle_send(uint8_t *buf, uint8_t size) +{ + _radio->lock(); + _radio->send(buf, size); + _radio->unlock(); +} + +uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t *new_channel) +{ + if (!phy_params.custom_channelplans_supported) { + return 0; + } + + uint8_t status = 0x03; + + if (new_channel->frequency == 0) { + // Remove + if (remove_channel(channel_id) == false) { + status &= 0xFC; + } + } else { + new_channel->band = lookup_band_for_frequency(new_channel->frequency); + switch (add_channel(new_channel, channel_id)) { + case LORAWAN_STATUS_OK: { + break; + } + case LORAWAN_STATUS_FREQUENCY_INVALID: { + status &= 0xFE; + break; + } + case LORAWAN_STATUS_DATARATE_INVALID: { + status &= 0xFD; + break; + } + case LORAWAN_STATUS_FREQ_AND_DR_INVALID: { + status &= 0xFC; + break; + } + default: { + status &= 0xFC; + break; + } + } + } + + return status; +} + +int32_t LoRaPHY::get_random(int32_t min, int32_t max) +{ + return (int32_t) rand() % (max - min + 1) + min; +} + +bool LoRaPHY::verify_channel_DR(uint16_t *channel_mask, int8_t dr) +{ + 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, (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; + } + } + } + + return false; +} + +bool LoRaPHY::val_in_range(int8_t value, int8_t min, int8_t max) +{ + if ((value >= min) && (value <= max)) { + return true; + } + + return false; +} + +bool LoRaPHY::disable_channel(uint16_t *channel_mask, uint8_t id, + uint8_t max_channels_num) +{ + uint8_t index = id / 16; + + if ((index > phy_params.channels.mask_size) || (id >= max_channels_num)) { + return false; + } + + // Deactivate channel + mask_bit_clear(channel_mask, id); + + return true; +} + +uint8_t LoRaPHY::count_bits(uint16_t mask, uint8_t nbBits) +{ + uint8_t nbActiveBits = 0; + + for (uint8_t j = 0; j < nbBits; j++) { + if (mask_bit_test(&mask, j)) { + nbActiveBits++; + } + } + + return nbActiveBits; +} + +uint8_t LoRaPHY::num_active_channels(uint16_t *channel_mask, uint8_t start_idx, + uint8_t stop_idx) +{ + uint8_t nb_channels = 0; + + if (channel_mask == NULL) { + return 0; + } + + for (uint8_t i = start_idx; i < stop_idx; i++) { + nb_channels += count_bits(channel_mask[i], 16); + } + + return nb_channels; +} + +void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t len) +{ + if ((dest_mask != NULL) && (src_mask != NULL)) { + for (uint8_t i = 0; i < len; i++) { + dest_mask[i] = src_mask[i]; + } + } +} + +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; + channel_params_t *channel_list = phy_params.channels.channel_list; + + if (joined == true) { + band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; + return; + } + + band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; + band_table[channel_list[channel].band].last_join_tx_time = last_tx_done_time; + +} + +lorawan_time_t LoRaPHY::update_band_timeoff(bool joined, bool duty_cycle, + band_t *bands, uint8_t nb_bands) +{ + lorawan_time_t next_tx_delay = (lorawan_time_t)(-1); + + // Update bands Time OFF + for (uint8_t i = 0; i < nb_bands; i++) { + if (MBED_CONF_LORA_DUTY_CYCLE_ON_JOIN && joined == false) { + uint32_t txDoneTime = MAX(_lora_time->get_elapsed_time(bands[i].last_join_tx_time), + (duty_cycle == true) ? + _lora_time->get_elapsed_time(bands[i].last_tx_time) : 0); + + if (bands[i].off_time <= txDoneTime) { + bands[i].off_time = 0; + } + + if (bands[i].off_time != 0) { + next_tx_delay = MIN(bands[i].off_time - txDoneTime, next_tx_delay); + // add a random delay from 200ms to a 1000ms + next_tx_delay += (rand() % 800 + 200); + } + } else { + // if network has been joined + if (duty_cycle == true) { + + if (bands[i].off_time <= _lora_time->get_elapsed_time(bands[i].last_tx_time)) { + bands[i].off_time = 0; + } + + if (bands[i].off_time != 0) { + next_tx_delay = MIN(bands[i].off_time - _lora_time->get_elapsed_time(bands[i].last_tx_time), + next_tx_delay); + } + } else { + // if duty cycle is not on + next_tx_delay = 0; + bands[i].off_time = 0; + } + } + } + + return next_tx_delay; +} + +uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t *payload, + uint8_t payload_size, + link_adr_params_t *params) +{ + uint8_t ret_index = 0; + + if (payload_size >= 5) { + + // Parse datarate and tx power + params->datarate = payload[1]; + params->tx_power = params->datarate & 0x0F; + params->datarate = (params->datarate >> 4) & 0x0F; + + // Parse ChMask + params->channel_mask = (uint16_t) payload[2]; + params->channel_mask |= (uint16_t) payload[3] << 8; + + // Parse ChMaskCtrl and nbRep + params->nb_rep = payload[4]; + params->ch_mask_ctrl = (params->nb_rep >> 4) & 0x07; + params->nb_rep &= 0x0F; + + // LinkAdrReq has 4 bytes length + 1 byte CMD + ret_index = 5; + } + + return ret_index; +} + +uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params, + int8_t *dr, int8_t *tx_pow, uint8_t *nb_rep) +{ + uint8_t status = verify_params->status; + int8_t datarate = verify_params->datarate; + int8_t tx_power = verify_params->tx_power; + int8_t nb_repetitions = verify_params->nb_rep; + + // Handle the case when ADR is off. + if (verify_params->adr_enabled == false) { + // When ADR is off, we are allowed to change the channels mask and the NbRep, + // if the datarate and the TX power of the LinkAdrReq are set to 0x0F. + if ((verify_params->datarate != 0x0F) || (verify_params->tx_power != 0x0F)) { + status = 0; + nb_repetitions = verify_params->current_nb_rep; + } + + // Get the current datarate and tx power + datarate = verify_params->current_datarate; + tx_power = verify_params->current_tx_power; + } + + if (status != 0) { + // Verify channel datarate + 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) == false) { + // Verify if the maximum TX power is exceeded + if (phy_params.max_tx_power > tx_power) { + // Apply maximum TX power. Accept TX power. + tx_power = phy_params.max_tx_power; + } else { + status &= 0xFB; // TxPower KO + } + } + } + + // If the status is ok, verify the NbRep + if (status == 0x07 && nb_repetitions == 0) { + // Restore the default value according to the LoRaWAN specification + nb_repetitions = 1; + } + + // Apply changes + *dr = datarate; + *tx_pow = tx_power; + *nb_rep = nb_repetitions; + + return status; +} + +float LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth) +{ + // in milliseconds + return ((float)(1 << phy_dr) / (float) bandwidth * 1000); +} + +float LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr) +{ + return (8.0f / (float) phy_dr); // 1 symbol equals 1 byte +} + + +void LoRaPHY::get_rx_window_params(float t_symb, uint8_t min_rx_symb, + float error_fudge, float wakeup_time, + uint32_t *window_length, uint32_t *window_length_ms, + int32_t *window_offset, + uint8_t phy_dr) +{ + float target_rx_window_offset; + float window_len_in_ms; + + if (phy_params.fsk_supported && phy_dr == phy_params.max_rx_datarate) { + min_rx_symb = MAX_PREAMBLE_LENGTH; + } + + // We wish to be as close as possible to the actual start of data, i.e., + // we are interested in the preamble symbols which are at the tail of the + // preamble sequence. + target_rx_window_offset = (MAX_PREAMBLE_LENGTH - min_rx_symb) * t_symb; //in ms + + // Actual window offset in ms in response to timing error fudge factor and + // radio wakeup/turned around time. + *window_offset = floor(target_rx_window_offset - error_fudge - wakeup_time); + + // possible wait for next symbol start if we start inside the preamble + float possible_wait_for_symb_start = MIN(t_symb, + ((2 * error_fudge) + wakeup_time + TICK_GRANULARITY_JITTER)); + + // how early we might start reception relative to transmit start (so negative if before transmit starts) + float earliest_possible_start_time = *window_offset - error_fudge - TICK_GRANULARITY_JITTER; + + // time in (ms) we may have to wait for the other side to start transmission + float possible_wait_for_transmit = -earliest_possible_start_time; + + // Minimum reception time plus extra time (in ms) we may have turned on before the + // other side started transmission + window_len_in_ms = (min_rx_symb * t_symb) + MAX(possible_wait_for_transmit, possible_wait_for_symb_start); + + // Setting the window_length in terms of 'symbols' for LoRa modulation or + // in terms of 'bytes' for FSK + *window_length = (uint32_t) ceil(window_len_in_ms / t_symb); + *window_length_ms = window_len_in_ms; +} + +int8_t LoRaPHY::compute_tx_power(int8_t tx_power_idx, float max_eirp, + float antenna_gain) +{ + int8_t phy_tx_power = 0; + + phy_tx_power = (int8_t) floor((max_eirp - (tx_power_idx * 2U)) - antenna_gain); + + return phy_tx_power; +} + + +int8_t LoRaPHY::get_next_lower_dr(int8_t dr, int8_t min_dr) +{ + uint8_t next_lower_dr = dr; + + do { + if (next_lower_dr != min_dr) { + next_lower_dr -= 1; + } + } while ((next_lower_dr != min_dr) && !is_datarate_supported(next_lower_dr)); + + return next_lower_dr; +} + +uint8_t LoRaPHY::get_bandwidth(uint8_t dr) +{ + uint32_t *bandwidths = (uint32_t *) phy_params.bandwidths.table; + + switch (bandwidths[dr]) { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } +} + +uint8_t LoRaPHY::enabled_channel_count(uint8_t datarate, + const uint16_t *channel_mask, + uint8_t *channel_indices, + uint8_t *delayTx) +{ + uint8_t count = 0; + uint8_t delay_transmission = 0; + + for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) { + if (mask_bit_test(channel_mask, i)) { + + if (val_in_range(datarate, phy_params.channels.channel_list[i].dr_range.fields.min, + phy_params.channels.channel_list[i].dr_range.fields.max) == 0) { + // data rate range invalid for this channel + continue; + } + + band_t *band_table = (band_t *) phy_params.bands.table; + if (band_table[phy_params.channels.channel_list[i].band].off_time > 0) { + // Check if the band is available for transmission + delay_transmission++; + continue; + } + + // otherwise count the channel as enabled + channel_indices[count++] = i; + } + } + + *delayTx = delay_transmission; + + return count; +} + +bool LoRaPHY::is_datarate_supported(const int8_t datarate) const +{ + if (datarate < phy_params.datarates.size) { + return (((uint8_t *)phy_params.datarates.table)[datarate] != 0) ? true : false; + } else { + return false; + } +} + +void LoRaPHY::reset_to_default_values(loramac_protocol_params *params, bool init) +{ + if (init) { + params->is_dutycycle_on = phy_params.duty_cycle_enabled; + + params->sys_params.max_rx_win_time = phy_params.max_rx_window; + + params->sys_params.recv_delay1 = phy_params.recv_delay1; + + params->sys_params.recv_delay2 = phy_params.recv_delay2; + + params->sys_params.join_accept_delay1 = phy_params.join_accept_delay1; + + params->sys_params.join_accept_delay2 = phy_params.join_accept_delay2; + + params->sys_params.downlink_dwell_time = phy_params.dl_dwell_time_setting; + } + + params->sys_params.channel_tx_power = get_default_tx_power(); + + // We shall always start with highest achievable data rate. + // Subsequent decrease in data rate will mean increase in range henceforth. + params->sys_params.channel_data_rate = get_default_max_tx_datarate(); + + params->sys_params.rx1_dr_offset = phy_params.default_rx1_dr_offset; + + params->sys_params.rx2_channel.frequency = get_default_rx2_frequency(); + + params->sys_params.rx2_channel.datarate = get_default_rx2_datarate(); + + params->sys_params.uplink_dwell_time = phy_params.ul_dwell_time_setting; + + params->sys_params.max_eirp = phy_params.default_max_eirp; + + params->sys_params.antenna_gain = phy_params.default_antenna_gain; +} + +int8_t LoRaPHY::get_next_lower_tx_datarate(int8_t datarate) +{ + if (phy_params.ul_dwell_time_setting == 0) { + return get_next_lower_dr(datarate, phy_params.min_tx_datarate); + } + + return get_next_lower_dr(datarate, phy_params.dwell_limit_datarate); + +} + +uint8_t LoRaPHY::get_minimum_rx_datarate() +{ + if (phy_params.dl_dwell_time_setting == 0) { + return phy_params.min_rx_datarate; + } + return phy_params.dwell_limit_datarate; +} + +uint8_t LoRaPHY::get_minimum_tx_datarate() +{ + if (phy_params.ul_dwell_time_setting == 0) { + return phy_params.min_tx_datarate; + } + return phy_params.dwell_limit_datarate; +} + +uint8_t LoRaPHY::get_default_tx_datarate() +{ + return phy_params.default_datarate; +} + +uint8_t LoRaPHY::get_default_max_tx_datarate() +{ + return phy_params.default_max_datarate; +} + +uint8_t LoRaPHY::get_default_tx_power() +{ + return phy_params.default_tx_power; +} + +uint8_t LoRaPHY::get_max_payload(uint8_t datarate, bool use_repeater) +{ + uint8_t *payload_table = NULL; + + if (use_repeater) { +// if (datarate >= phy_params.payloads_with_repeater.size) { +// //TODO: Can this ever happen? If yes, should we return 0? +// } + payload_table = (uint8_t *) phy_params.payloads_with_repeater.table; + } else { + payload_table = (uint8_t *) phy_params.payloads.table; + } + + return payload_table[datarate]; +} + +uint16_t LoRaPHY::get_maximum_frame_counter_gap() +{ + return phy_params.max_fcnt_gap; +} + +uint32_t LoRaPHY::get_ack_timeout() +{ + uint16_t ack_timeout_rnd = phy_params.ack_timeout_rnd; + return (phy_params.ack_timeout + get_random(0, ack_timeout_rnd)); +} + +uint32_t LoRaPHY::get_default_rx2_frequency() +{ + return phy_params.rx_window2_frequency; +} + +uint8_t LoRaPHY::get_default_rx2_datarate() +{ + return phy_params.rx_window2_datarate; +} + +uint16_t *LoRaPHY::get_channel_mask(bool get_default) +{ + if (get_default) { + return phy_params.channels.default_mask; + } + return phy_params.channels.mask; +} + +uint8_t LoRaPHY::get_max_nb_channels() +{ + return phy_params.max_channel_cnt; +} + +channel_params_t *LoRaPHY::get_phy_channels() +{ + return phy_params.channels.channel_list; +} + +bool LoRaPHY::is_custom_channel_plan_supported() +{ + return phy_params.custom_channelplans_supported; +} + +void LoRaPHY::restore_default_channels() +{ + // Restore channels default mask + for (uint8_t i = 0; i < phy_params.channels.mask_size; i++) { + phy_params.channels.mask[i] |= phy_params.channels.default_mask[i]; + } +} + +bool LoRaPHY::verify_rx_datarate(uint8_t datarate) +{ + if (is_datarate_supported(datarate)) { + if (phy_params.dl_dwell_time_setting == 0) { + //TODO: Check this! datarate must be same as minimum! Can be compared directly if OK + return val_in_range(datarate, + phy_params.min_rx_datarate, + phy_params.max_rx_datarate); + } else { + return val_in_range(datarate, + phy_params.dwell_limit_datarate, + phy_params.max_rx_datarate); + } + } + return false; +} + +bool LoRaPHY::verify_tx_datarate(uint8_t datarate, bool use_default) +{ + if (!is_datarate_supported(datarate)) { + return false; + } + + if (use_default) { + return val_in_range(datarate, phy_params.default_datarate, + phy_params.default_max_datarate); + } else if (phy_params.ul_dwell_time_setting == 0) { + return val_in_range(datarate, phy_params.min_tx_datarate, + phy_params.max_tx_datarate); + } else { + return val_in_range(datarate, phy_params.dwell_limit_datarate, + phy_params.max_tx_datarate); + } +} + +bool LoRaPHY::verify_tx_power(uint8_t tx_power) +{ + return val_in_range(tx_power, phy_params.max_tx_power, + phy_params.min_tx_power); +} + +bool LoRaPHY::verify_duty_cycle(bool cycle) +{ + if (cycle == phy_params.duty_cycle_enabled) { + return true; + } + return false; +} + +bool LoRaPHY::verify_nb_join_trials(uint8_t nb_join_trials) +{ + if (nb_join_trials < MBED_CONF_LORA_NB_TRIALS) { + return false; + } + return true; +} + +void LoRaPHY::apply_cf_list(const uint8_t *payload, uint8_t size) +{ + // if the underlying PHY doesn't support CF-List, ignore the request + if (!phy_params.cflist_supported) { + return; + } + + channel_params_t new_channel; + + // Setup default datarate range + new_channel.dr_range.value = (phy_params.default_max_datarate << 4) | + phy_params.default_datarate; + + // Size of the optional CF list + if (size != 16) { + return; + } + + // Last byte is RFU, don't take it into account + // NOTE: Currently the PHY layers supported by LoRaWAN who accept a CF-List + // define first 2 or 3 channels as default channels. this function is + // written keeping that in mind. If there would be a PHY in the future that + // accepts CF-list but have haphazard allocation of default channels, we + // should override this function in the implementation of that particular + // PHY. + for (uint8_t i = 0, channel_id = phy_params.default_channel_cnt; + channel_id < phy_params.max_channel_cnt; i += 3, channel_id++) { + if (channel_id < (phy_params.cflist_channel_cnt + phy_params.default_channel_cnt)) { + // Channel frequency + new_channel.frequency = (uint32_t) payload[i]; + new_channel.frequency |= ((uint32_t) payload[i + 1] << 8); + new_channel.frequency |= ((uint32_t) payload[i + 2] << 16); + new_channel.frequency *= 100; + + // Initialize alternative frequency to 0 + new_channel.rx1_frequency = 0; + } else { + new_channel.frequency = 0; + new_channel.dr_range.value = 0; + new_channel.rx1_frequency = 0; + } + + if (new_channel.frequency != 0) { + //lookup for band + new_channel.band = lookup_band_for_frequency(new_channel.frequency); + + // Try to add channel + add_channel(&new_channel, channel_id); + } else { + remove_channel(channel_id); + } + } +} + + +bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t &dr_out, + int8_t &tx_power_out, uint32_t &adr_ack_cnt) +{ + bool set_adr_ack_bit = false; + + uint16_t ack_limit_plus_delay = phy_params.adr_ack_limit + phy_params.adr_ack_delay; + + if (dr_out == phy_params.min_tx_datarate) { + adr_ack_cnt = 0; + return set_adr_ack_bit; + } + + if (adr_ack_cnt < phy_params.adr_ack_limit) { + return set_adr_ack_bit; + } + + // ADR ack counter is larger than ADR-ACK-LIMIT + set_adr_ack_bit = true; + tx_power_out = phy_params.max_tx_power; + + if (adr_ack_cnt >= ack_limit_plus_delay) { + if ((adr_ack_cnt % phy_params.adr_ack_delay) == 1) { + // Decrease the datarate + dr_out = get_next_lower_tx_datarate(dr_out); + + if (dr_out == phy_params.min_tx_datarate) { + // We must set adrAckReq to false as soon as we reach the lowest datarate + set_adr_ack_bit = false; + if (restore_channel_mask) { + // Re-enable default channels + restore_default_channels(); + } + } + } + } + + return set_adr_ack_bit; +} + +void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, + uint32_t rx_error, + rx_config_params_t *rx_conf_params) +{ + float t_symbol = 0.0; + + // Get the datarate, perform a boundary check + rx_conf_params->datarate = MIN(datarate, phy_params.max_rx_datarate); + + rx_conf_params->bandwidth = get_bandwidth(rx_conf_params->datarate); + + if (phy_params.fsk_supported && rx_conf_params->datarate == phy_params.max_rx_datarate) { + // FSK + t_symbol = compute_symb_timeout_fsk(((uint8_t *)phy_params.datarates.table)[rx_conf_params->datarate]); + } else { + // LoRa + t_symbol = compute_symb_timeout_lora(((uint8_t *)phy_params.datarates.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, (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME, + &rx_conf_params->window_timeout, &rx_conf_params->window_timeout_ms, + &rx_conf_params->window_offset, + rx_conf_params->datarate); +} + +uint32_t LoRaPHY::get_rx_time_on_air(uint8_t modem, uint16_t pkt_len) +{ + uint32_t toa = 0; + + _radio->lock(); + toa = _radio->time_on_air((radio_modems_t) modem, pkt_len); + _radio->unlock(); + + return toa; +} + +bool LoRaPHY::rx_config(rx_config_params_t *rx_conf) +{ + uint8_t dr = rx_conf->datarate; + uint8_t max_payload = 0; + uint8_t phy_dr = 0; + + // Read the physical datarate from the datarates table + uint8_t *datarate_table = (uint8_t *) phy_params.datarates.table; + uint8_t *payload_table = (uint8_t *) phy_params.payloads.table; + uint8_t *payload_with_repeater_table = (uint8_t *) phy_params.payloads_with_repeater.table; + + phy_dr = datarate_table[dr]; + + _radio->lock(); + + _radio->set_channel(rx_conf->frequency); + + // Radio configuration + if (dr == DR_7 && phy_params.fsk_supported) { + rx_conf->modem_type = MODEM_FSK; + _radio->set_rx_config((radio_modems_t) rx_conf->modem_type, 50000, phy_dr * 1000, 0, 83333, MAX_PREAMBLE_LENGTH, + rx_conf->window_timeout, false, 0, true, 0, 0, + false, rx_conf->is_rx_continuous); + } else { + rx_conf->modem_type = MODEM_LORA; + _radio->set_rx_config((radio_modems_t) rx_conf->modem_type, rx_conf->bandwidth, phy_dr, 1, 0, + MAX_PREAMBLE_LENGTH, + rx_conf->window_timeout, false, 0, false, 0, 0, + true, rx_conf->is_rx_continuous); + } + + if (rx_conf->is_repeater_supported) { + max_payload = payload_with_repeater_table[dr]; + } else { + max_payload = payload_table[dr]; + } + + _radio->set_max_payload_length((radio_modems_t) rx_conf->modem_type, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + _radio->unlock(); + + return true; +} + +bool LoRaPHY::tx_config(tx_config_params_t *tx_conf, int8_t *tx_power, + lorawan_time_t *tx_toa) +{ + radio_modems_t modem; + int8_t phy_dr = ((uint8_t *)phy_params.datarates.table)[tx_conf->datarate]; + channel_params_t *list = phy_params.channels.channel_list; + uint8_t band_idx = list[tx_conf->channel].band; + band_t *bands = (band_t *)phy_params.bands.table; + + // limit TX power if set to too much + tx_conf->tx_power = MAX(tx_conf->tx_power, bands[band_idx].max_tx_pwr); + + uint8_t bandwidth = get_bandwidth(tx_conf->datarate); + int8_t phy_tx_power = 0; + + // Calculate physical TX power + phy_tx_power = compute_tx_power(tx_conf->tx_power, tx_conf->max_eirp, + tx_conf->antenna_gain); + + _radio->lock(); + + // Setup the radio frequency + _radio->set_channel(list[tx_conf->channel].frequency); + + if (tx_conf->datarate == phy_params.max_tx_datarate) { + // High Speed FSK channel + modem = MODEM_FSK; + _radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth, + phy_dr * 1000, 0, MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, + false, true, 0, 0, false, 3000); + } else { + modem = MODEM_LORA; + _radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1, + MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, + false, true, 0, 0, false, 3000); + } + + // Setup maximum payload lenght of the radio driver + _radio->set_max_payload_length(modem, tx_conf->pkt_len); + // Get the time-on-air of the next tx frame + *tx_toa = _radio->time_on_air(modem, tx_conf->pkt_len); + + _radio->unlock(); + + *tx_power = tx_conf->tx_power; + + return true; +} + +uint8_t LoRaPHY::link_ADR_request(adr_req_params_t *link_adr_req, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, uint8_t *nb_bytes_processed) +{ + uint8_t status = 0x07; + link_adr_params_t adr_settings; + uint8_t next_index = 0; + uint8_t bytes_processed = 0; + + // rather than dynamically allocating memory, we choose to set + // a channel mask list size of unity here as we know that all + // the PHY layer implementations who have more than 16 channels, i.e., + // have channel mask list size more than unity, override this method. + uint16_t temp_channel_mask[1] = {0}; + + verify_adr_params_t verify_params; + + while (bytes_processed < link_adr_req->payload_size && + link_adr_req->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { + // Get ADR request parameters + next_index = parse_link_ADR_req(&(link_adr_req->payload[bytes_processed]), + link_adr_req->payload_size - bytes_processed, + &adr_settings); + + if (next_index == 0) { + bytes_processed = 0; + // break loop, malformed packet + break; + } + + // Update bytes processed + bytes_processed += next_index; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + temp_channel_mask[0] = adr_settings.channel_mask; + + // Verify channels mask + if (adr_settings.ch_mask_ctrl == 0 && temp_channel_mask[0] == 0) { + status &= 0xFE; // Channel mask KO + } + + // channel mask applies to first 16 channels + if (adr_settings.ch_mask_ctrl == 0 || adr_settings.ch_mask_ctrl == 6) { + + for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) { + + // turn on all channels if channel mask control is 6 + if (adr_settings.ch_mask_ctrl == 6) { + if (phy_params.channels.channel_list[i].frequency != 0) { + mask_bit_set(temp_channel_mask, i); + } + + continue; + } + + // if channel mask control is 0, we test the bits and + // frequencies and change the status if we find a discrepancy + if ((mask_bit_test(temp_channel_mask, i)) && + (phy_params.channels.channel_list[i].frequency == 0)) { + // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } else { + // Channel mask control applies to RFUs + status &= 0xFE; // Channel mask KO + } + } + + if (bytes_processed == 0) { + *nb_bytes_processed = 0; + return status; + } + + if (is_datarate_supported(adr_settings.datarate)) { + verify_params.status = status; + + verify_params.adr_enabled = link_adr_req->adr_enabled; + verify_params.current_datarate = link_adr_req->current_datarate; + verify_params.current_tx_power = link_adr_req->current_tx_power; + verify_params.current_nb_rep = link_adr_req->current_nb_trans; + + verify_params.datarate = adr_settings.datarate; + verify_params.tx_power = adr_settings.tx_power; + verify_params.nb_rep = adr_settings.nb_rep; + + + verify_params.channel_mask = temp_channel_mask; + + // Verify the parameters and update, if necessary + status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, + &adr_settings.tx_power, &adr_settings.nb_rep); + } else { + status &= 0xFD; // Datarate KO + } + + // Update channelsMask if everything is correct + if (status == 0x07) { + // Set the channels mask to a default value + memset(phy_params.channels.mask, 0, + sizeof(uint16_t)*phy_params.channels.mask_size); + + // Update the channels mask + copy_channel_mask(phy_params.channels.mask, temp_channel_mask, + phy_params.channels.mask_size); + } + + // Update status variables + *dr_out = adr_settings.datarate; + *tx_power_out = adr_settings.tx_power; + *nb_rep_out = adr_settings.nb_rep; + *nb_bytes_processed = bytes_processed; + + return status; +} + +uint8_t LoRaPHY::accept_rx_param_setup_req(rx_param_setup_req_t *params) +{ + uint8_t status = 0x07; + + if (lookup_band_for_frequency(params->frequency) < 0) { + status &= 0xFE; + } + + // Verify radio frequency + if (_radio->check_rf_frequency(params->frequency) == false) { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if (val_in_range(params->datarate, phy_params.min_rx_datarate, + phy_params.max_rx_datarate) == 0) { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (val_in_range(params->dr_offset, phy_params.min_rx1_dr_offset, + phy_params.max_rx1_dr_offset) == 0) { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; +} + +bool LoRaPHY::accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time) +{ + if (phy_params.accept_tx_param_setup_req) { + phy_params.ul_dwell_time_setting = ul_dwell_time; + phy_params.dl_dwell_time_setting = dl_dwell_time; + } + + return phy_params.accept_tx_param_setup_req; +} + +int LoRaPHY::lookup_band_for_frequency(uint32_t freq) const +{ + // check all sub bands (if there are sub-bands) to check if the given + // frequency falls into any of the frequency ranges + + for (int band = 0; band < phy_params.bands.size; band++) { + if (verify_frequency_for_band(freq, band)) { + return band; + } + } + + return -1; +} + +bool LoRaPHY::verify_frequency_for_band(uint32_t freq, uint8_t band) const +{ + band_t *bands_table = (band_t *)phy_params.bands.table; + + if (freq <= bands_table[band].higher_band_freq + && freq >= bands_table[band].lower_band_freq) { + return true; + } else { + return false; + } +} + +uint8_t LoRaPHY::dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency) +{ + if (!phy_params.dl_channel_req_supported) { + return 0; + } + + uint8_t status = 0x03; + + // Verify if the frequency is supported + int band = lookup_band_for_frequency(rx1_frequency); + if (band < 0) { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if (phy_params.channels.channel_list[channel_id].frequency == 0) { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if (status == 0x03) { + phy_params.channels.channel_list[channel_id].rx1_frequency = rx1_frequency; + } + + return status; +} + +/** + * Alternate datarate algorithm for join requests. + * - We check from the PHY and take note of total + * number of data rates available upto the default data rate for + * default channels. + * + * - Application sets a total number of re-trials for a Join Request, i.e., + * MBED_CONF_LORA_NB_TRIALS. So MAC layer will send us a counter + * nb_trials < MBED_CONF_LORA_NB_TRIALS which is the current number of trial. + * + * - We roll over total available datarates and pick one according to the + * number of trial sequentially. + * + * - We always start from the Default Data rate and and set the next lower + * data rate for every iteration. + * + * - MAC layer will stop when maximum number of re-trials, i.e., + * MBED_CONF_LORA_NB_TRIALS is achieved. + * + * So essentially MBED_CONF_LORA_NB_TRIALS should be a multiple of range of + * data rates available. For example, in EU868 band, default max. data rate is + * DR_5 and min. data rate is DR_0, so total data rates available are 6. + * + * Hence MBED_CONF_LORA_NB_TRIALS should be a multiple of 6. Setting, + * MBED_CONF_LORA_NB_TRIALS = 6 would mean that every data rate will be tried + * exactly once starting from the largest and finishing at the smallest. + * + * PHY layers which do not have datarates scheme similar to EU band will ofcourse + * override this method. + */ +int8_t LoRaPHY::get_alternate_DR(uint8_t nb_trials) +{ + int8_t datarate = 0; + uint8_t total_nb_datrates = (phy_params.default_max_datarate - phy_params.min_tx_datarate) + 1; + + uint8_t res = nb_trials % total_nb_datrates; + + if (res == 0) { + datarate = phy_params.min_tx_datarate; + } else if (res == 1) { + datarate = phy_params.default_max_datarate; + } else { + datarate = (phy_params.default_max_datarate - res) + 1; + } + + return datarate; +} + +void LoRaPHY::calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, + lorawan_time_t elapsed_time, lorawan_time_t tx_toa) +{ + band_t *band_table = (band_t *) phy_params.bands.table; + channel_params_t *channel_list = phy_params.channels.channel_list; + + uint8_t band_idx = channel_list[channel].band; + uint16_t duty_cycle = band_table[band_idx].duty_cycle; + uint16_t join_duty_cycle = 0; + + // Reset time-off to initial value. + band_table[band_idx].off_time = 0; + + if (MBED_CONF_LORA_DUTY_CYCLE_ON_JOIN && joined == false) { + // Get the join duty cycle + if (elapsed_time < 3600000) { + join_duty_cycle = BACKOFF_DC_1_HOUR; + } else if (elapsed_time < (3600000 + 36000000)) { + join_duty_cycle = BACKOFF_DC_10_HOURS; + } else { + join_duty_cycle = BACKOFF_DC_24_HOURS; + } + + // Apply the most restricting duty cycle + duty_cycle = MAX(duty_cycle, join_duty_cycle); + } + + // No back-off if the last frame was not a join request and when the + // duty cycle is not enabled + if (dc_enabled == false && last_tx_was_join_req == false) { + band_table[band_idx].off_time = 0; + } else { + // Apply band time-off. + band_table[band_idx].off_time = tx_toa * duty_cycle - tx_toa; + } +} + +lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t *params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff) +{ + uint8_t channel_count = 0; + uint8_t delay_tx = 0; + + // Note here that the PHY layer implementations which have more than + // 16 channels at their disposal, override this function. That's why + // it is safe to assume that we are dealing with a block of 16 channels + // i.e., EU like implementations. So rather than dynamically allocating + // memory we chose to use a magic number of 16 + uint8_t enabled_channels[16]; + + memset(enabled_channels, 0xFF, sizeof(uint8_t) * 16); + + lorawan_time_t next_tx_delay = 0; + band_t *band_table = (band_t *) phy_params.bands.table; + + if (num_active_channels(phy_params.channels.mask, 0, + phy_params.channels.mask_size) == 0) { + + // Reactivate default channels + copy_channel_mask(phy_params.channels.mask, + phy_params.channels.default_mask, + phy_params.channels.mask_size); + } + + if (params->aggregate_timeoff + <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregate_timeoff = 0; + + // Update bands Time OFF + next_tx_delay = update_band_timeoff(params->joined, + params->dc_enabled, + band_table, phy_params.bands.size); + + // Search how many channels are enabled + channel_count = enabled_channel_count(params->current_datarate, + phy_params.channels.mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + next_tx_delay = params->aggregate_timeoff - + _lora_time->get_elapsed_time(params->last_aggregate_tx_time); + } + + if (channel_count > 0) { + // We found a valid channel + *channel = enabled_channels[get_random(0, channel_count - 1)]; + *time = 0; + return LORAWAN_STATUS_OK; + } + + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = next_tx_delay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + + // Datarate not supported by any channel, restore defaults + copy_channel_mask(phy_params.channels.mask, + phy_params.channels.default_mask, + phy_params.channels.mask_size); + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; +} + +lorawan_status_t LoRaPHY::add_channel(const channel_params_t *new_channel, + uint8_t id) +{ + bool dr_invalid = false; + bool freq_invalid = false; + + if (!phy_params.custom_channelplans_supported + || id >= phy_params.max_channel_cnt) { + + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if (val_in_range(new_channel->dr_range.fields.min, + phy_params.min_tx_datarate, + phy_params.max_tx_datarate) == 0) { + dr_invalid = true; + } + + if (val_in_range(new_channel->dr_range.fields.max, phy_params.min_tx_datarate, + phy_params.max_tx_datarate) == 0) { + dr_invalid = true; + } + + if (new_channel->dr_range.fields.min > new_channel->dr_range.fields.max) { + dr_invalid = true; + } + + // 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 != DR_0) { + dr_invalid = true; + } + + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if (val_in_range(new_channel->dr_range.fields.max, + phy_params.default_max_datarate, + phy_params.max_tx_datarate) == 0) { + dr_invalid = true; + } + + // We are not allowed to change the frequency + if (new_channel->frequency != phy_params.channels.channel_list[id].frequency) { + freq_invalid = true; + } + } + + // Check frequency + if (!freq_invalid) { + if (new_channel->band >= phy_params.bands.size + || verify_frequency_for_band(new_channel->frequency, + new_channel->band) == false) { + freq_invalid = true; + } + } + + // Check status + if (dr_invalid && freq_invalid) { + return LORAWAN_STATUS_FREQ_AND_DR_INVALID; + } + + if (dr_invalid) { + return LORAWAN_STATUS_DATARATE_INVALID; + } + + if (freq_invalid) { + return LORAWAN_STATUS_FREQUENCY_INVALID; + } + + memmove(&(phy_params.channels.channel_list[id]), new_channel, sizeof(channel_params_t)); + + phy_params.channels.channel_list[id].band = new_channel->band; + + mask_bit_set(phy_params.channels.mask, id); + + return LORAWAN_STATUS_OK; +} + +bool LoRaPHY::remove_channel(uint8_t channel_id) +{ + // upper layers are checking if the custom channel planning is supported or + // not. So we don't need to worry about that + if (mask_bit_test(phy_params.channels.default_mask, channel_id)) { + return false; + } + + + // Remove the channel from the list of channels + const channel_params_t empty_channel = { 0, 0, {0}, 0 }; + phy_params.channels.channel_list[channel_id] = empty_channel; + + return disable_channel(phy_params.channels.mask, channel_id, + phy_params.max_channel_cnt); +} + +void LoRaPHY::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) +{ + band_t *bands_table = (band_t *) phy_params.bands.table; + channel_params_t *channels = phy_params.channels.channel_list; + + if (params->tx_power > bands_table[channels[params->channel].band].max_tx_pwr) { + params->tx_power = bands_table[channels[params->channel].band].max_tx_pwr; + } + + int8_t phy_tx_power = 0; + uint32_t frequency = 0; + + if (given_frequency == 0) { + frequency = channels[params->channel].frequency; + } else { + frequency = given_frequency; + } + + // Calculate physical TX power + if (params->max_eirp > 0 && params->antenna_gain > 0) { + phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp, + params->antenna_gain); + } else { + phy_tx_power = params->tx_power; + } + + _radio->lock(); + _radio->set_tx_continuous_wave(frequency, phy_tx_power, params->timeout); + _radio->unlock(); +} + +uint8_t LoRaPHY::apply_DR_offset(int8_t dr, int8_t dr_offset) +{ + int8_t datarate = dr - dr_offset; + + if (datarate < 0) { + datarate = phy_params.min_tx_datarate; + } + + return datarate; +} + + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHY.h b/connectivity/lorawan/lorastack/phy/LoRaPHY.h new file mode 100644 index 0000000..786d0b6 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHY.h @@ -0,0 +1,683 @@ +/** + * @file LoRaPHY.h + * + * @brief An abstract class providing radio object to children and + * provide base for implementing LoRa PHY layer + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * Description: LoRa PHY layer + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_BASE_ +#define MBED_OS_LORAPHY_BASE_ + +#include "platform/NonCopyable.h" + +#include "system/LoRaWANTimer.h" +#include "LoRaRadio.h" +#include "lora_phy_ds.h" + +/** LoRaPHY Class + * Parent class for LoRa regional PHY implementations + */ +class LoRaPHY : private mbed::NonCopyable { + +public: + virtual ~LoRaPHY(); + + /** Initialize LoRaPHY + * + * LoRaMac calls this to initialize LoRaPHY. + * + * @param lora_time a pointer to LoRaWANTimeHandler object + */ + void initialize(LoRaWANTimeHandler *lora_time); + + /** Stores a reference to Radio object. + * + * Application is responsible for constructing a 'LoRaRadio' object + * which is passed down to the PHY layer. + * + * @param radio a reference to radio driver object + */ + void set_radio_instance(LoRaRadio &radio); + + /** Puts radio in sleep mode. + * + * Requests the radio driver to enter sleep mode. + */ + void put_radio_to_sleep(void); + + /** Puts radio in standby mode. + * + * Requests the radio driver to enter standby mode. + */ + void put_radio_to_standby(void); + + /** Puts radio in receive mode. + * + * Requests the radio driver to enter receive mode. + */ + void handle_receive(void); + + /** Delegates MAC layer request to transmit packet. + * + * @param buf a pointer to the data which needs to be transmitted + * + * @param size size of the data in bytes + */ + void handle_send(uint8_t *buf, uint8_t size); + + /** Enables/Disables public network mode. + * + * Public and private LoRaWAN network constitute different preambles and + * Net IDs. This API isused to tell the radio which network mode is in use. + * + * @param set true or false + */ + void setup_public_network_mode(bool set); + + /** Provides a random number from radio. + * + * Returns a 32-bit random unsigned integer value based upon RSSI + * measurements. + * + * @return a 32-bit long random number + * + */ + uint32_t get_radio_rng(); + + /** + * @brief calculate_backoff Calculates and applies duty cycle back-off time. + * Explicitly updates the band time-off. + * + * @param joined Set to true, if the node has already joined a network, otherwise false. + * @param last_tx_was_join_req Set to true, if the last uplink was a join request. + * @param dc_enabled Set to true, if the duty cycle is enabled, otherwise false. + * @param channel The current channel index. + * @param elapsed_time Elapsed time since the start of the node. + * @param tx_toa Time-on-air of the last transmission. + */ + void calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, + lorawan_time_t elapsed_time, lorawan_time_t tx_toa); + + /** + * Tests if a channel is on or off in the channel mask + */ + bool mask_bit_test(const uint16_t *mask, unsigned bit); + + /** + * Tests if a channel is on or off in the channel mask + */ + void mask_bit_set(uint16_t *mask, unsigned bit); + + /** + * Tests if a channel is on or off in the channel mask + */ + void mask_bit_clear(uint16_t *mask, unsigned bit); + + /** Entertain a new channel request MAC command. + * + * MAC command subsystem processes the new channel request coming form + * the network server and then MAC layer asks the PHY layer to entertain + * the request. + * + * @param channel_id The channel ID. + * @param new_channel A pointer to the new channel's parameters. + * + * @return bit mask, according to the LoRaWAN spec 1.0.2. + */ + virtual uint8_t request_new_channel(int8_t channel_id, channel_params_t *new_channel); + + /** Process PHY layer state after a successful transmission. + * @brief set_last_tx_done Updates times of the last transmission for the particular channel and + * band upon which last transmission took place. + * @param channel The channel in use. + * @param joined Boolean telling if node has joined the network. + * @param last_tx_done_time The last TX done time. + */ + virtual void set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time); + + /** Enables default channels only. + * + * Falls back to a channel mask where only default channels are enabled, all + * other channels are disabled. + */ + virtual void restore_default_channels(); + + /** Processes the incoming CF-list. + * + * Handles the payload containing CF-list and enables channels defined + * therein. + * + * @param payload Payload to process. + * @param size Size of the payload. + * + */ + virtual void apply_cf_list(const uint8_t *payload, uint8_t size); + + /** Calculates the next datarate to set, when ADR is on or off. + * + * @param restore_channel_mask A boolean set restore channel mask in case + * of failure. + * + * @param dr_out The calculated datarate for the next TX. + * + * @param tx_power_out The TX power for the next TX. + * + * @param adr_ack_counter The calculated ADR acknowledgement counter. + * + * @return True, if an ADR request should be performed. + */ + bool get_next_ADR(bool restore_channel_mask, int8_t &dr_out, + int8_t &tx_power_out, uint32_t &adr_ack_counter); + + /** Configure radio reception. + * + * @param [in] config A pointer to the RX configuration. + * + * @return True, if the configuration was applied successfully. + */ + virtual bool rx_config(rx_config_params_t *config); + + /** Computing Receive Windows + * + * The algorithm tries to calculate the length of receive windows (i.e., + * the minimum time it should remain to acquire a lock on the Preamble + * for synchronization) and the error offset which compensates for the system + * timing errors. Basic idea behind the algorithm is to optimize for the + * reception of last 'min_rx_symbols' symbols out of transmitted Premable + * symbols. The algorithm compensates for the clock drifts, tick granularity + * and system wake up time (from sleep state) by opening the window early for + * the lower SFs. For higher SFs, the symbol time is large enough that we can + * afford to open late (hence the positive offset). + * The table below shows the calculated values for SF7 to SF12 with 125 kHz + * bandwidth. + * + * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ + * | SF | BW (kHz) | rx_error (ms) | wake_up (ms) | min_rx_symbols | window_timeout(symb) | window_offset(ms) | + * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ + * | 7 | 125 | 5 | 5 | 5 | 18 | -7 | + * | 8 | 125 | 5 | 5 | 5 | 10 | -4 | + * | 9 | 125 | 5 | 5 | 5 | 6 | 2 | + * | 10 | 125 | 5 | 5 | 5 | 6 | 14 | + * | 11 | 125 | 5 | 5 | 5 | 6 | 39 | + * | 12 | 125 | 5 | 5 | 5 | 6 | 88 | + * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ + * + * For example for SF7, the receive window will open at downlink start time + * plus the offset calculated and will remain open for the length window_timeout. + * + * Symbol time = 1.024 ms + * Downlink start: T = Tx + 1s (+/- 20 us) + * | + * | + * | + * | + * | + * +---+---+---+---+---+---+---+---+ + * | 8 Preamble Symbols | + * +---+---+---+---+---+---+---+---+ + * | RX Window start time = T +/- Offset + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | | | | | | | | | | | | | | | | | | | + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + * Similarly for SF12: + * + * Symbol time = 32.768 ms + * Downlink start: T = Tx + 1s (+/- 20 us) + * | + * | + * | + * | + * | + * +---+---+---+---+---+---+---+---+ + * | 8 Preamble Symbols | + * +---+---+---+---+---+---+---+---+ + * | RX Window start time = T +/- Offset + * +---+---+---+---+---+---+ + * | | | | | | | + * +---+---+---+---+---+---+ + */ + /*! + * Computes the RX window timeout and offset. + * + * @param [in] datarate The RX window datarate index to be used. + * + * @param [in] min_rx_symbols The minimum number of symbols required to + * detect an RX frame. + * + * @param [in] rx_error The maximum timing error of the receiver + * in milliseconds. The receiver will turn on + * in a [-rxError : +rxError] ms interval around + * RxOffset. + * + * @param [out] rx_conf_params Pointer to the structure that needs to be + * filled with receive window parameters. + * + */ + virtual void compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, + uint32_t rx_error, + rx_config_params_t *rx_conf_params); + + /** Configure radio transmission. + * + * @param [in] tx_config Structure containing tx parameters. + * + * @param [out] tx_power The TX power which will be set. + * + * @param [out] tx_toa The time-on-air of the frame. + * + * @return True, if the configuration was applied successfully. + */ + virtual bool tx_config(tx_config_params_t *tx_config, int8_t *tx_power, + lorawan_time_t *tx_toa); + + /** Processes a Link ADR Request. + * + * @param [in] params A pointer ADR request parameters. + * + * @param [out] dr_out The datarate applied. + * + * @param [out] tx_power_out The TX power applied. + * + * @param [out] nb_rep_out The number of repetitions to apply. + * + * @param [out] nb_bytes_parsed The number of bytes parsed. + * + * @return The status of the operation, according to the LoRaMAC specification. + */ + virtual uint8_t link_ADR_request(adr_req_params_t *params, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, + uint8_t *nb_bytes_parsed); + + /** Accept or rejects RxParamSetupReq MAC command + * + * The function processes a RX parameter setup request in response to + * server MAC command for RX setup. + * + * @param [in] params A pointer to rx parameter setup request. + * + * @return The status of the operation, according to the LoRaWAN specification. + */ + virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); + + /** + * @brief accept_tx_param_setup_req Makes decision whether to accept or reject TxParamSetupReq MAC command. + * + * @param ul_dwell_time The uplink dwell time. + * @param dl_dwell_time The downlink dwell time. + * + * @return True to let the MAC know that the request is + * accepted and MAC can apply TX parameters received + * form Network Server. Otherwise false is returned. + */ + virtual bool accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time); + + /** Processes a DlChannelReq MAC command. + * + * @param channel_id The channel ID to add the frequency. + * @param rx1_frequency The alternative frequency for the Rx1 window. + * + * @return The status of the operation, according to the LoRaWAN specification. + */ + virtual uint8_t dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency); + + /** Alternates the datarate of the channel for the join request. + * + * @param nb_trials Number of trials to be made on one given data rate. + * + * @return The datarate to apply . + */ + virtual int8_t get_alternate_DR(uint8_t nb_trials); + + /** Searches and sets the next available channel. + * + * If there are multiple channels found available, one of them is selected + * randomly. + * + * @param [in] nextChanParams Parameters for the next channel. + * + * @param [out] channel The next channel to use for TX. + * + * @param [out] time The time to wait for the next transmission according to the duty cycle. + * + * @param [out] aggregatedTimeOff Updates the aggregated time off. + * + * @return Function status [1: OK, 0: Unable to find a channel on the current datarate]. + */ + virtual lorawan_status_t set_next_channel(channel_selection_params_t *nextChanParams, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregatedTimeOff); + + /** Adds a channel to the channel list. + * + * Verifies the channel parameters and if everything is found legitimate, + * adds that particular channel to the channel list and updates the channel + * mask. + * + * @param [in] new_channel A pointer to the parameters for the new channel. + * @param [in] id Channel ID + * + * @return LORAWAN_STATUS_OK if everything goes fine, negative error code + * otherwise. + */ + virtual lorawan_status_t add_channel(const channel_params_t *new_channel, uint8_t id); + + /** Removes a channel from the channel list. + * + * @param [in] channel_id Index of the channel to be removed + * + * @return True, if the channel was removed successfully. + */ + virtual bool remove_channel(uint8_t channel_id); + + /** Puts the radio into continuous wave mode. + * + * @param [in] continuous_wave A pointer to the function parameters. + * + * @param [in] frequency Frequency to transmit at + */ + virtual void set_tx_cont_mode(cw_mode_params_t *continuous_wave, + uint32_t frequency = 0); + + /** Computes new data rate according to the given offset + * + * @param [in] dr The current datarate. + * + * @param [in] dr_offset The offset to be applied. + * + * @return The computed datarate. + */ + virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); + + /** + * @brief reset_to_default_values resets some parameters to default values + * @param params Pointer to MAC protocol parameters which will be reset + * @param init If true, most of the values will be modified + */ + void reset_to_default_values(loramac_protocol_params *params, bool init = false); + +public: + /** + * @brief get_next_lower_tx_datarate Gets the next lower datarate + * @param datarate Current TX datarate + * @return Lower datarate than given one or minimum if lower cannot be found anymore + */ + int8_t get_next_lower_tx_datarate(int8_t datarate); + + /** + * @brief get_minimum_rx_datarate Gets the minimum RX datarate supported by a device + * @return Minimum RX datarate + */ + uint8_t get_minimum_rx_datarate(); + + /** + * @brief get_minimum_tx_datarate Gets the minimum TX datarate supported by a device + * @return Minimum TX datarate + */ + uint8_t get_minimum_tx_datarate(); + + /** + * @brief get_default_tx_datarate Gets the default TX datarate + * @return default TX datarate + */ + uint8_t get_default_tx_datarate(); + + /** + * @brief get_default_max_tx_datarate Gets the maximum achievable data rate for + * LoRa modulation. This will always be the highest data rate achievable with + * LoRa as defined in the regional specifications. + * @return Maximum achievable data rate with LoRa modulation. + */ + uint8_t get_default_max_tx_datarate(); + + /** + * @brief get_default_tx_power Gets the default TX power + * @return Default TX power + */ + uint8_t get_default_tx_power(); + + /** + * @brief get_max_payload Gets maximum amount in bytes which device can send + * @param datarate A datarate to use + * @param use_repeater If true repeater table is used, otherwise payloads table is used + * @return Maximum number of bytes for payload + */ + uint8_t get_max_payload(uint8_t datarate, bool use_repeater = false); + + /** + * @brief get_maximum_frame_counter_gap Gets maximum frame counter gap + * @return Maximum frame counter gap + */ + uint16_t get_maximum_frame_counter_gap(); + + /** + * @brief get_ack_timeout Gets timeout value for ACK to be received + * @return ACK timeout + */ + uint32_t get_ack_timeout(); + + /** + * @brief get_default_rx2_frequency Gets default RX2 frequency + * @return RX2 frequency + */ + uint32_t get_default_rx2_frequency(); + + /** + * @brief get_default_rx2_datarate Gets default RX2 datarate + * @return RX2 datarate + */ + uint8_t get_default_rx2_datarate(); + + /** + * @brief get_channel_mask Gets the channel mask + * @param get_default If true the default mask is returned, otherwise the current mask is returned + * @return A channel mask + */ + uint16_t *get_channel_mask(bool get_default = false); + + /** + * @brief get_max_nb_channels Gets maximum number of channels supported + * @return Number of channels + */ + uint8_t get_max_nb_channels(); + + /** + * @brief get_phy_channels Gets PHY channels + * @return PHY channels + */ + channel_params_t *get_phy_channels(); + + /** + * @brief is_custom_channel_plan_supported Checks if custom channel plan is supported + * @return True if custom channel plan is supported, false otherwise + */ + bool is_custom_channel_plan_supported(); + + /** + * @brief get_rx_time_on_air(...) calculates the time the received spent on air + * @return time spent on air in milliseconds + */ + uint32_t get_rx_time_on_air(uint8_t modem, uint16_t pkt_len); + +public: //Verifiers + + /** + * @brief verify_rx_datarate Verifies that given RX datarate is valid + * @param datarate Datarate to check + * @return true if given datarate is valid, false otherwise + */ + bool verify_rx_datarate(uint8_t datarate); + + /** + * @brief verify_tx_datarate Verifies that given TX datarate is valid + * @param datarate Datarate to check + * @param use_default If true validation is done against default value + * @return true if given datarate is valid, false otherwise + */ + bool verify_tx_datarate(uint8_t datarate, bool use_default = false); + + /** + * @brief verify_tx_power Verifies that given TX power is valid + * @param tx_power Power to check + * @return True if valid, false otherwise + */ + bool verify_tx_power(uint8_t tx_power); + + /** + * @brief verify_duty_cycle Verifies that given cycle is valid + * @param cycle Cycle to check + * @return True if valid, false otherwise + */ + bool verify_duty_cycle(bool cycle); + + /** + * @brief verify_nb_join_trials Verifies that given number of trials is valid + * @param nb_join_trials Number to check + * @return True if valid, false otherwise + */ + bool verify_nb_join_trials(uint8_t nb_join_trials); + +protected: + LoRaPHY(); + + /** + * Looks up corresponding band for a frequency. Returns -1 if not in any band. + */ + int lookup_band_for_frequency(uint32_t freq) const; + + /** + * Verifies, if a frequency is within a given band. + */ + virtual bool verify_frequency_for_band(uint32_t freq, uint8_t band) const; + + /** + * Verifies, if a value is in a given range. + */ + bool val_in_range(int8_t value, int8_t min, int8_t max); + + /** + * Verifies, if a datarate is available on an active channel. + */ + bool verify_channel_DR(uint16_t *channelsMask, int8_t dr); + + /** + * Disables a channel in a given channels mask. + */ + bool disable_channel(uint16_t *channel_mask, uint8_t id, uint8_t max_channels); + + /** + * Counts number of bits on in a given mask + */ + uint8_t count_bits(uint16_t mask, uint8_t nb_bits); + + /** + * Counts the number of active channels in a given channels mask. + */ + uint8_t num_active_channels(uint16_t *channel_mask, uint8_t start_idx, + uint8_t stop_idx); + + /** + * Copy channel masks. + */ + void copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t len); + + /** + * Updates the time-offs of the bands. + */ + lorawan_time_t update_band_timeoff(bool joined, bool dutyCycle, band_t *bands, + uint8_t nb_bands); + + /** + * Parses the parameter of an LinkAdrRequest. + */ + uint8_t parse_link_ADR_req(const uint8_t *payload, uint8_t payload_size, + link_adr_params_t *adr_params); + + /** + * Verifies and updates the datarate, the TX power and the number of repetitions + * of a LinkAdrRequest. + */ + 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 RX window timeout and the RX window offset. + */ + void get_rx_window_params(float t_symbol, uint8_t min_rx_symbols, + float rx_error, float wakeup_time, + uint32_t *window_length, uint32_t *window_length_ms, + int32_t *window_offset, + uint8_t phy_dr); + + /** + * Computes the txPower, based on the max EIRP and the antenna gain. + */ + int8_t compute_tx_power(int8_t txPowerIndex, float maxEirp, float antennaGain); + + /** + * Provides a random number in the range provided. + */ + int32_t get_random(int32_t min, int32_t max); + + /** + * Get next lower data rate + */ + int8_t get_next_lower_dr(int8_t dr, int8_t min_dr); + + /** + * Get channel bandwidth depending upon data rate table index + */ + uint8_t get_bandwidth(uint8_t dr_index); + + uint8_t enabled_channel_count(uint8_t datarate, + const uint16_t *mask, uint8_t *enabledChannels, + uint8_t *delayTx); + + bool is_datarate_supported(const int8_t datarate) const; + +private: + + /** + * Computes the symbol time for LoRa modulation. + */ + float compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth); + + /** + * Computes the symbol time for FSK modulation. + */ + float compute_symb_timeout_fsk(uint8_t phy_dr); + +protected: + LoRaRadio *_radio; + LoRaWANTimeHandler *_lora_time; + loraphy_params_t phy_params; +}; + +#endif /* MBED_OS_LORAPHY_BASE_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.cpp new file mode 100644 index 0000000..e5e37e8 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.cpp @@ -0,0 +1,425 @@ +/** + * @file LoRaPHYAS923.cpp + * + * @brief Implements LoRaPHY for Asia-Pacific 923 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYAS923.h" +#include "lora_phy_ds.h" + +/*! + * Number of default channels + */ +#define AS923_NUMB_DEFAULT_CHANNELS 2 + +/*! + * Number of channels to apply for the CF list + */ +#define AS923_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define AS923_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define AS923_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define AS923_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define AS923_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define AS923_DEFAULT_DATARATE DR_2 + +#define AS923_DEFAULT_MAX_DATARATE DR_5 + +/*! + * The minimum datarate which is used when the + * dwell time is limited. + */ +#define AS923_DWELL_LIMIT_DATARATE DR_2 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define AS923_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define AS923_MAX_RX1_DR_OFFSET 7 + +/*! + * Default Rx1 receive datarate offset + */ +#define AS923_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define AS923_MIN_TX_POWER TX_POWER_7 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define AS923_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define AS923_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define AS923_DEFAULT_MAX_EIRP 16.0f + +/*! + * Default antenna gain + */ +#define AS923_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define AS923_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define AS923_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define AS923_DUTY_CYCLE_ENABLED 0 + +/*! + * Maximum RX window duration + */ +#define AS923_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define AS923_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define AS923_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define AS923_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define AS923_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define AS923_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define AS923_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define AS923_ACK_TIMEOUT_RND 1000 + +#if ( AS923_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define AS923_RX_WND_2_FREQ 923200000 + +/*! + * Second reception window channel datarate definition. + */ +#define AS923_RX_WND_2_DR DR_2 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t AS923_BAND0 = {100, AS923_MAX_TX_POWER, 0, 0, 0, 923000000, 928000000}; // 1.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t AS923_LC1 = { 923200000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t AS923_LC2 = { 923400000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define AS923_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) ) + +/*! + * RSSI threshold for a free channel [dBm] + */ +#define AS923_RSSI_FREE_TH -85 + +/*! + * Specifies the time the node performs a carrier sense + */ +#define AS923_CARRIER_SENSE_TIME 6 + +/*! + * Data rates table definition + */ +static const uint8_t datarates_AS923[] = {12, 11, 10, 9, 8, 7, 7, 50}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_AS923[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; + +#if (MBED_CONF_LORA_DWELL_TIME == 0) +static const uint8_t max_payload_table[] = {51, 51, 51, 115, 242, 242, 242, 242}; +static const uint8_t max_payload_table_with_repeater[] = {51, 51, 51, 115, 222, 222, 222, 222}; +#else +// this is the default, i.e., +static const uint8_t max_payload_table[] = {0, 0, 11, 53, 125, 242, 242, 242}; +static const uint8_t max_payload_table_with_repeater[] = {0, 0, 11, 53, 125, 242, 242, 242}; +#endif + +/*! + * Effective datarate offsets for receive window 1. + */ +static const int8_t rx1_dr_offset_AS923[] = {0, 1, 2, 3, 4, 5, -1, -2}; + +LoRaPHYAS923::LoRaPHYAS923() +{ + bands[0] = AS923_BAND0; + + // Default Channels are always enabled in the channel list, + // rest will be added later + channels[0] = AS923_LC1; + channels[0].band = 0; + channels[1] = AS923_LC2; + channels[1].band = 0; + + // Initialize the default channel mask + default_channel_mask[0] = LC(1) + LC(2); + + // Update the channel mask list + copy_channel_mask(channel_mask, default_channel_mask, AS923_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = AS923_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = AS923_CHANNEL_MASK_SIZE; + + // set bands for AS923 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = AS923_MAX_NB_BANDS; + + // set bandwidths available in AS923 spectrum + phy_params.bandwidths.table = (void *) bandwidths_AS923; + phy_params.bandwidths.size = 8; + + // set data rates available in AS923 spectrum + phy_params.datarates.table = (void *) datarates_AS923; + phy_params.datarates.size = 8; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payload_table; + phy_params.payloads.size = 8; + phy_params.payloads_with_repeater.table = (void *) max_payload_table_with_repeater; + phy_params.payloads_with_repeater.size = 8; + + // dwell time setting, 400 ms + phy_params.ul_dwell_time_setting = 1; + phy_params.dl_dwell_time_setting = 1; + phy_params.dwell_limit_datarate = AS923_DWELL_LIMIT_DATARATE; + + phy_params.duty_cycle_enabled = AS923_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = true; + phy_params.fsk_supported = true; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = AS923_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = AS923_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = AS923_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = AS923_TX_MIN_DATARATE; + phy_params.max_tx_datarate = AS923_TX_MAX_DATARATE; + phy_params.min_rx_datarate = AS923_RX_MIN_DATARATE; + phy_params.max_rx_datarate = AS923_RX_MAX_DATARATE; + phy_params.default_datarate = AS923_DEFAULT_DATARATE; + phy_params.default_max_datarate = AS923_DEFAULT_MAX_DATARATE; + phy_params.min_rx1_dr_offset = AS923_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = AS923_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = AS923_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = AS923_MIN_TX_POWER; + phy_params.max_tx_power = AS923_MAX_TX_POWER; + phy_params.default_tx_power = AS923_DEFAULT_TX_POWER; + phy_params.default_max_eirp = AS923_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = AS923_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = AS923_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = AS923_ADR_ACK_DELAY; + phy_params.max_rx_window = AS923_MAX_RX_WINDOW; + phy_params.recv_delay1 = AS923_RECEIVE_DELAY1; + phy_params.recv_delay2 = AS923_RECEIVE_DELAY2; + phy_params.join_channel_mask = AS923_JOIN_CHANNELS; + phy_params.join_accept_delay1 = AS923_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = AS923_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = AS923_MAX_FCNT_GAP; + phy_params.ack_timeout = AS923_ACKTIMEOUT; + phy_params.ack_timeout_rnd = AS923_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = AS923_RX_WND_2_DR; + phy_params.rx_window2_frequency = AS923_RX_WND_2_FREQ; +} + +LoRaPHYAS923::~LoRaPHYAS923() +{ +} + +int8_t LoRaPHYAS923::get_alternate_DR(uint8_t nb_trials) +{ + // Only AS923_DWELL_LIMIT_DATARATE is supported + return AS923_DWELL_LIMIT_DATARATE; +} + +lorawan_status_t LoRaPHYAS923::set_next_channel(channel_selection_params_t *next_channel_prams, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff) +{ + uint8_t next_channel_idx = 0; + uint8_t nb_enabled_channels = 0; + uint8_t delay_tx = 0; + uint8_t enabled_channels[AS923_MAX_NB_CHANNELS] = { 0 }; + lorawan_time_t next_tx_delay = 0; + + if (num_active_channels(channel_mask, 0, 1) == 0) { + // Reactivate default channels + channel_mask[0] |= LC(1) + LC(2); + } + + if (next_channel_prams->aggregate_timeoff <= _lora_time->get_elapsed_time(next_channel_prams->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregate_timeoff = 0; + + // Update bands Time OFF + next_tx_delay = update_band_timeoff(next_channel_prams->joined, + next_channel_prams->dc_enabled, + bands, AS923_MAX_NB_BANDS); + + // Search how many channels are enabled + nb_enabled_channels = enabled_channel_count(next_channel_prams->current_datarate, + channel_mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + next_tx_delay = next_channel_prams->aggregate_timeoff - _lora_time->get_elapsed_time(next_channel_prams->last_aggregate_tx_time); + } + + if (nb_enabled_channels > 0) { + + _radio->lock(); + + for (uint8_t i = 0, j = get_random(0, nb_enabled_channels - 1); i < AS923_MAX_NB_CHANNELS; i++) { + next_channel_idx = enabled_channels[j]; + j = (j + 1) % nb_enabled_channels; + + // Perform carrier sense for AS923_CARRIER_SENSE_TIME + // If the channel is free, we can stop the LBT mechanism + + if (_radio->perform_carrier_sense(MODEM_LORA, + channels[next_channel_idx].frequency, + AS923_RSSI_FREE_TH, + AS923_CARRIER_SENSE_TIME) == true) { + // Free channel found + _radio->unlock(); + *channel = next_channel_idx; + *time = 0; + return LORAWAN_STATUS_OK; + } + } + _radio->unlock(); + return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; + } else { + + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = next_tx_delay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + + // Datarate not supported by any channel, restore defaults + channel_mask[0] |= LC(1) + LC(2); + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; + } +} + +uint8_t LoRaPHYAS923::apply_DR_offset(int8_t dr, int8_t dr_offset) +{ + // Initialize minDr for a downlink dwell time configuration of 0 + int8_t min_dr = DR_0; + + // Update the minDR for a downlink dwell time configuration of 1 + if (phy_params.dl_dwell_time_setting == 1) { + min_dr = AS923_DWELL_LIMIT_DATARATE; + } + + // Apply offset formula + return MIN(DR_5, MAX(min_dr, dr - rx1_dr_offset_AS923[dr_offset])); +} + + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.h b/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.h new file mode 100644 index 0000000..e222c0d --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYAS923.h @@ -0,0 +1,73 @@ +/** + * @file LoRaPHYAS923.h + * + * @brief Implements LoRaPHY for Asia-Pacific 923 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_AS923_H_ +#define MBED_OS_LORAPHY_AS923_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define AS923_MAX_NB_CHANNELS 16 + +/*! + * Maximum number of bands + */ +#define AS923_MAX_NB_BANDS 1 + +#define AS923_CHANNEL_MASK_SIZE 1 + +class LoRaPHYAS923 : public LoRaPHY { + +public: + LoRaPHYAS923(); + virtual ~LoRaPHYAS923(); + + virtual int8_t get_alternate_DR(uint8_t nb_trials); + + virtual lorawan_status_t set_next_channel(channel_selection_params_t *nextChanParams, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregatedTimeOff); + + virtual uint8_t apply_DR_offset(int8_t dr, int8_t drOffset); + +private: + channel_params_t channels[AS923_MAX_NB_CHANNELS]; + band_t bands[AS923_MAX_NB_BANDS]; + uint16_t channel_mask[AS923_CHANNEL_MASK_SIZE]; + uint16_t default_channel_mask[AS923_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_AS923_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.cpp new file mode 100644 index 0000000..24c8519 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.cpp @@ -0,0 +1,663 @@ +/** + * @file LoRaPHYAU915.cpp + * + * @brief Implements LoRaPHY for Australian 915 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include "LoRaPHYAU915.h" +#include "lora_phy_ds.h" + +/*! + * Minimal datarate that can be used by the node + */ +#define AU915_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define AU915_TX_MAX_DATARATE DR_6 + +/*! + * Minimal datarate that can be used by the node + */ +#define AU915_RX_MIN_DATARATE DR_8 + +/*! + * Maximal datarate that can be used by the node + */ +#define AU915_RX_MAX_DATARATE DR_13 + +/*! + * Default datarate used by the node + */ +#define AU915_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define AU915_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define AU915_MAX_RX1_DR_OFFSET 6 + +/*! + * Default Rx1 receive datarate offset + */ +#define AU915_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define AU915_MIN_TX_POWER TX_POWER_10 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define AU915_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define AU915_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define AU915_DEFAULT_MAX_EIRP 30.0f + +/*! + * Default antenna gain + */ +#define AU915_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define AU915_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define AU915_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define AU915_DUTY_CYCLE_ENABLED 0 + +/*! + * Maximum RX window duration + */ +#define AU915_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define AU915_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define AU915_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define AU915_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define AU915_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define AU915_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define AU915_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define AU915_ACK_TIMEOUT_RND 1000 + +/*! + * Second reception window channel frequency definition. + */ +#define AU915_RX_WND_2_FREQ 923300000 + +/*! + * Second reception window channel datarate definition. + */ +#define AU915_RX_WND_2_DR DR_8 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t AU915_BAND0 = {1, AU915_MAX_TX_POWER, 0, 0, 0, 915200000, 927800000}; // 100.0 % + +/*! + * Defines the first channel for RX window 1 for US band + */ +#define AU915_FIRST_RX1_CHANNEL ((uint32_t) 923300000) + +/*! + * Defines the last channel for RX window 1 for US band + */ +#define AU915_LAST_RX1_CHANNEL ((uint32_t) 927500000) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define AU915_STEPWIDTH_RX1_CHANNEL ((uint32_t) 600000) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_AU915[] = {12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_AU915[] = { 125000, 125000, 125000, 125000, + 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, + 0, 0 + }; + +/*! + * Up/Down link data rates offset definition + */ +static const int8_t datarate_offsets_AU915[7][6] = { { + DR_8, DR_8, DR_8, DR_8, + DR_8, DR_8 + }, // DR_0 + { DR_9, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_1 + { DR_10, DR_9, DR_8, DR_8, DR_8, DR_8 }, // DR_2 + { DR_11, DR_10, DR_9, DR_8, DR_8, DR_8 }, // DR_3 + { DR_12, DR_11, DR_10, DR_9, DR_8, DR_8 }, // DR_4 + { DR_13, DR_12, DR_11, DR_10, DR_9, DR_8 }, // DR_5 + { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6 +}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payload_AU915[] = { 51, 51, 51, 115, 242, 242, + 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 + }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payload_with_repeater_AU915[] = { 51, 51, 51, 115, + 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 + }; + +static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; + +static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; + +LoRaPHYAU915::LoRaPHYAU915() +{ + bands[0] = AU915_BAND0; + + // Activate Channels + // 125 kHz channels Upstream only + for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++) { + channels[i].frequency = 915200000 + i * 200000; + channels[i].dr_range.value = (DR_5 << 4) | DR_0; + channels[i].band = 0; + } + // 500 kHz channels + // Upstream and downstream both + for (uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++) { + channels[i].frequency = 915900000 + (i - (AU915_MAX_NB_CHANNELS - 8)) * 1600000; + channels[i].dr_range.value = (DR_6 << 4) | DR_6; + channels[i].band = 0; + } + + // Initialize channels default mask + // All channels are default channels here + // Join request needs to alternate between 125 KHz and 500 KHz channels + // randomly. Fill in the default channel mask depending upon the given + // fsb_mask + fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, + default_channel_mask, AU915_CHANNEL_MASK_SIZE); + + memset(channel_mask, 0, sizeof(channel_mask)); + memset(current_channel_mask, 0, sizeof(current_channel_mask)); + + // Copy channels default mask + copy_channel_mask(channel_mask, default_channel_mask, AU915_CHANNEL_MASK_SIZE); + + // Copy into current channels mask + // This mask is used to keep track of the channels which were used in + // previous transmissions as the AU915 band doesn't allow concurrent + // transmission on the same channel + copy_channel_mask(current_channel_mask, channel_mask, AU915_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = AU915_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = AU915_CHANNEL_MASK_SIZE; + + // set bands for AU915 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = AU915_MAX_NB_BANDS; + + // set bandwidths available in AU915 spectrum + phy_params.bandwidths.table = (void *) bandwidths_AU915; + phy_params.bandwidths.size = 16; + + // set data rates available in AU915 spectrum + phy_params.datarates.table = (void *) datarates_AU915; + phy_params.datarates.size = 16; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payload_AU915; + phy_params.payloads.size = 16; + phy_params.payloads_with_repeater.table = (void *) max_payload_with_repeater_AU915; + phy_params.payloads_with_repeater.size = 16; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + phy_params.dwell_limit_datarate = AU915_DEFAULT_DATARATE; + + phy_params.duty_cycle_enabled = AU915_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.custom_channelplans_supported = false; + phy_params.cflist_supported = false; + phy_params.fsk_supported = false; + + phy_params.default_channel_cnt = AU915_MAX_NB_CHANNELS; + phy_params.max_channel_cnt = AU915_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = 0; + phy_params.min_tx_datarate = AU915_TX_MIN_DATARATE; + phy_params.max_tx_datarate = AU915_TX_MAX_DATARATE; + phy_params.min_rx_datarate = AU915_RX_MIN_DATARATE; + phy_params.max_rx_datarate = AU915_RX_MAX_DATARATE; + phy_params.default_datarate = AU915_DEFAULT_DATARATE; + phy_params.default_max_datarate = AU915_TX_MAX_DATARATE; + phy_params.min_rx1_dr_offset = AU915_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = AU915_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = AU915_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = AU915_MIN_TX_POWER; + phy_params.max_tx_power = AU915_MAX_TX_POWER; + phy_params.default_tx_power = AU915_DEFAULT_TX_POWER; + phy_params.default_max_eirp = AU915_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = AU915_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = AU915_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = AU915_ADR_ACK_DELAY; + phy_params.max_rx_window = AU915_MAX_RX_WINDOW; + phy_params.recv_delay1 = AU915_RECEIVE_DELAY1; + phy_params.recv_delay2 = AU915_RECEIVE_DELAY2; + + phy_params.join_accept_delay1 = AU915_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = AU915_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = AU915_MAX_FCNT_GAP; + phy_params.ack_timeout = AU915_ACKTIMEOUT; + phy_params.ack_timeout_rnd = AU915_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = AU915_RX_WND_2_DR; + phy_params.rx_window2_frequency = AU915_RX_WND_2_FREQ; +} + +LoRaPHYAU915::~LoRaPHYAU915() +{ +} + +bool LoRaPHYAU915::rx_config(rx_config_params_t *params) +{ + int8_t dr = params->datarate; + uint8_t max_payload = 0; + int8_t phy_dr = 0; + uint32_t frequency = params->frequency; + + if (_radio->get_status() != RF_IDLE) { + return false; + } + + if (params->rx_slot == RX_SLOT_WIN_1) { + // Apply window 1 frequency + frequency = AU915_FIRST_RX1_CHANNEL + + (params->channel % 8) * AU915_STEPWIDTH_RX1_CHANNEL; + // Caller may print the frequency to log so update it to match actual frequency + params->frequency = frequency; + } + + // Read the physical datarate from the datarates table + phy_dr = datarates_AU915[dr]; + + _radio->lock(); + + _radio->set_channel(frequency); + + // Radio configuration + _radio->set_rx_config(MODEM_LORA, params->bandwidth, phy_dr, 1, 0, 8, + params->window_timeout, false, 0, false, 0, 0, true, + params->is_rx_continuous); + + if (params->is_repeater_supported == true) { + max_payload = max_payload_with_repeater_AU915[dr]; + } else { + max_payload = max_payload_AU915[dr]; + } + _radio->set_max_payload_length(MODEM_LORA, + max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + _radio->unlock(); + + return true; +} + +bool LoRaPHYAU915::tx_config(tx_config_params_t *params, int8_t *tx_power, + lorawan_time_t *tx_toa) +{ + int8_t phy_dr = datarates_AU915[params->datarate]; + + if (params->tx_power > bands[channels[params->channel].band].max_tx_pwr) { + params->tx_power = bands[channels[params->channel].band].max_tx_pwr; + } + + uint32_t bandwidth = get_bandwidth(params->datarate); + int8_t phy_tx_power = 0; + + // Calculate physical TX power + phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp, + params->antenna_gain); + + // setting up radio tx configurations + + _radio->lock(); + + _radio->set_channel(channels[params->channel].frequency); + + _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, + false, true, 0, 0, false, 3000); + + // Setup maximum payload lenght of the radio driver + _radio->set_max_payload_length(MODEM_LORA, params->pkt_len); + + *tx_toa = _radio->time_on_air(MODEM_LORA, params->pkt_len); + + _radio->unlock(); + + *tx_power = params->tx_power; + + return true; +} + +uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t *params, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, + uint8_t *nb_bytes_parsed) +{ + uint8_t status = 0x07; + link_adr_params_t adr_settings = {}; + uint8_t next_index = 0; + uint8_t bytes_processed = 0; + uint16_t temp_channel_masks[AU915_CHANNEL_MASK_SIZE] = { 0, 0, 0, 0, 0}; + + verify_adr_params_t verify_params; + + // Initialize local copy of channels mask + copy_channel_mask(temp_channel_masks, channel_mask, AU915_CHANNEL_MASK_SIZE); + + while (bytes_processed < params->payload_size && + params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { + next_index = parse_link_ADR_req(&(params->payload[bytes_processed]), + params->payload_size, + &adr_settings); + + if (next_index == 0) { + bytes_processed = 0; + // break loop, malformed packet + break; + } + + // Update bytes processed + bytes_processed += next_index; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (adr_settings.ch_mask_ctrl == 6) { + // Enable all 125 kHz channels + fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, + AU915_CHANNEL_MASK_SIZE - 1); + + // Apply chMask to channels 64 to 71 + temp_channel_masks[4] = adr_settings.channel_mask; + } else if (adr_settings.ch_mask_ctrl == 7) { + // Disable all 125 kHz channels + fill_channel_mask_with_value(temp_channel_masks, 0x0000, + AU915_CHANNEL_MASK_SIZE - 1); + + // Apply chMask to channels 64 to 71 + temp_channel_masks[4] = adr_settings.channel_mask; + } else if (adr_settings.ch_mask_ctrl == 5) { + // RFU + status &= 0xFE; // Channel mask KO + } else { + temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; + } + } + + if (bytes_processed == 0) { + *nb_bytes_parsed = 0; + return status; + } + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if ((adr_settings.datarate < DR_6) + && (num_active_channels(temp_channel_masks, 0, 4) < 2)) { + status &= 0xFE; // Channel mask KO + } + + verify_params.status = status; + verify_params.adr_enabled = params->adr_enabled; + verify_params.datarate = adr_settings.datarate; + verify_params.tx_power = adr_settings.tx_power; + verify_params.nb_rep = adr_settings.nb_rep; + verify_params.current_datarate = params->current_datarate; + verify_params.current_tx_power = params->current_tx_power; + verify_params.current_nb_rep = params->current_nb_trans; + verify_params.channel_mask = temp_channel_masks; + + + // Verify the parameters and update, if necessary + status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, + &adr_settings.tx_power, &adr_settings.nb_rep); + + // Update cchannel mask if everything is correct + if (status == 0x07) { + // Copy Mask + copy_channel_mask(channel_mask, temp_channel_masks, AU915_CHANNEL_MASK_SIZE); + + intersect_channel_mask(channel_mask, current_channel_mask, + AU915_CHANNEL_MASK_SIZE); + } + + // Update status variables + *dr_out = adr_settings.datarate; + *tx_power_out = adr_settings.tx_power; + *nb_rep_out = adr_settings.nb_rep; + *nb_bytes_parsed = bytes_processed; + + return status; +} + +uint8_t LoRaPHYAU915::accept_rx_param_setup_req(rx_param_setup_req_t *params) +{ + uint8_t status = 0x07; + uint32_t freq = params->frequency; + + // Verify radio frequency + _radio->lock(); + + if ((_radio->check_rf_frequency(freq) == false) + || (freq < AU915_FIRST_RX1_CHANNEL) + || (freq > AU915_LAST_RX1_CHANNEL) + || (((freq - (uint32_t) AU915_FIRST_RX1_CHANNEL) + % (uint32_t) AU915_STEPWIDTH_RX1_CHANNEL) != 0)) { + status &= 0xFE; // Channel frequency KO + } + + _radio->unlock(); + + // Verify datarate + if (val_in_range(params->datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE) == 0) { + status &= 0xFD; // Datarate KO + } + + if ((params->datarate == DR_7) || (params->datarate > DR_13)) { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (val_in_range(params->dr_offset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET) == 0) { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; +} + +int8_t LoRaPHYAU915::get_alternate_DR(uint8_t nb_trials) +{ + int8_t datarate = 0; + + if ((nb_trials & 0x01) == 0x01) { + datarate = DR_6; + } else { + datarate = DR_0; + } + + return datarate; +} + +lorawan_status_t LoRaPHYAU915::set_next_channel(channel_selection_params_t *next_chan_params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregated_timeOff) +{ + uint8_t nb_enabled_channels = 0; + uint8_t delay_tx = 0; + uint8_t enabled_channels[AU915_MAX_NB_CHANNELS] = { 0 }; + lorawan_time_t next_tx_delay = 0; + + // Count 125kHz channels + if (num_active_channels(current_channel_mask, 0, 4) == 0) { + // Reactivate 125 kHz default channels + copy_channel_mask(current_channel_mask, channel_mask, 4); + } + + // Check other channels + if ((next_chan_params->current_datarate >= DR_6) + && (current_channel_mask[4] & 0x00FF) == 0) { + // fall back to 500 kHz default channels + current_channel_mask[4] = channel_mask[4]; + } + + if (next_chan_params->aggregate_timeoff <= _lora_time->get_elapsed_time(next_chan_params->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregated_timeOff = 0; + + // Update bands Time OFF + next_tx_delay = update_band_timeoff(next_chan_params->joined, + next_chan_params->dc_enabled, + bands, AU915_MAX_NB_BANDS); + + // Search how many channels are enabled + nb_enabled_channels = enabled_channel_count(next_chan_params->current_datarate, + current_channel_mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + next_tx_delay = next_chan_params->aggregate_timeoff - _lora_time->get_elapsed_time(next_chan_params->last_aggregate_tx_time); + } + + if (nb_enabled_channels > 0) { + // We found a valid channel + *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; + // Disable the channel in the mask + disable_channel(current_channel_mask, *channel, AU915_MAX_NB_CHANNELS); + + *time = 0; + return LORAWAN_STATUS_OK; + } else { + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = next_tx_delay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + // Datarate not supported by any channel + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; + } +} + +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/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.h b/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.h new file mode 100644 index 0000000..cdcce73 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYAU915.h @@ -0,0 +1,132 @@ +/** + * @file LoRaPHYAU915.h + * + * @brief Implements LoRaPHY for Australian 915 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_AU915_H_ + +#define MBED_OS_LORAPHY_AU915_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +// Definitions +/*! + * LoRaMac maximum number of channels + */ +#define AU915_MAX_NB_CHANNELS 72 + +/*! + * LoRaMac maximum number of bands + */ +#define AU915_MAX_NB_BANDS 1 + +#define AU915_CHANNEL_MASK_SIZE 5 + +class LoRaPHYAU915 : public LoRaPHY { + +public: + + LoRaPHYAU915(); + virtual ~LoRaPHYAU915(); + + virtual bool rx_config(rx_config_params_t *config); + + virtual bool tx_config(tx_config_params_t *config, int8_t *txPower, + lorawan_time_t *txTimeOnAir); + + virtual uint8_t link_ADR_request(adr_req_params_t *params, + int8_t *drOut, int8_t *txPowOut, + uint8_t *nbRepOut, + uint8_t *nbBytesParsed); + + virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); + + virtual int8_t get_alternate_DR(uint8_t nb_trials); + + virtual lorawan_status_t set_next_channel(channel_selection_params_t *next_chan_params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff); + + 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: + + /*! + * LoRaMAC channels + */ + channel_params_t channels[AU915_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[AU915_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[AU915_CHANNEL_MASK_SIZE]; + + /*! + * Previously used channel mask + */ + uint16_t current_channel_mask[AU915_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac channels default mask + */ + uint16_t default_channel_mask[AU915_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_AU915_H_ */ + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.cpp new file mode 100644 index 0000000..3385cfe --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.cpp @@ -0,0 +1,576 @@ +/** + * @file LoRaPHYCN470.cpp + * + * @brief Implements LoRaPHY for Chinese 470 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYCN470.h" +#include "lora_phy_ds.h" + +/*! + * Minimal datarate that can be used by the node + */ +#define CN470_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define CN470_TX_MAX_DATARATE DR_5 + +/*! + * Minimal datarate that can be used by the node + */ +#define CN470_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define CN470_RX_MAX_DATARATE DR_5 + +/*! + * Default datarate used by the node + */ +#define CN470_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define CN470_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define CN470_MAX_RX1_DR_OFFSET 3 + +/*! + * Default Rx1 receive datarate offset + */ +#define CN470_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define CN470_MIN_TX_POWER TX_POWER_7 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define CN470_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define CN470_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define CN470_DEFAULT_MAX_EIRP 19.15f + +/*! + * Default antenna gain + */ +#define CN470_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define CN470_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define CN470_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define CN470_DUTY_CYCLE_ENABLED 0 + +/*! + * Maximum RX window duration + */ +#define CN470_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define CN470_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define CN470_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define CN470_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define CN470_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define CN470_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define CN470_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define CN470_ACK_TIMEOUT_RND 1000 + +/*! + * Second reception window channel frequency definition. + */ +#define CN470_RX_WND_2_FREQ 505300000 + +/*! + * Second reception window channel datarate definition. + */ +#define CN470_RX_WND_2_DR DR_0 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t CN470_BAND0 = {1, CN470_MAX_TX_POWER, 0, 0, 0}; // 100.0 % + +/*! + * Defines the first channel for RX window 1 for CN470 band + */ +#define CN470_FIRST_RX1_CHANNEL ((uint32_t) 500300000) + +/*! + * Defines the last channel for RX window 1 for CN470 band + */ +#define CN470_LAST_RX1_CHANNEL ((uint32_t) 509700000) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define CN470_STEPWIDTH_RX1_CHANNEL ((uint32_t) 200000) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_CN470[] = {12, 11, 10, 9, 8, 7}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_CN470[] = {125000, 125000, 125000, 125000, 125000, 125000}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_CN470[] = {51, 51, 51, 115, 222, 222}; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater_CN470[] = {51, 51, 51, 115, 222, 222}; + + +LoRaPHYCN470::LoRaPHYCN470() +{ + static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK_CHINA; + + bands[0] = CN470_BAND0; + + // Channels + // 125 kHz channels + for (uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++) { + channels[i].frequency = 470300000 + i * 200000; + channels[i].dr_range.value = (DR_5 << 4) | DR_0; + channels[i].band = 0; + } + + // Initialize the channels default mask + for (uint8_t i = 0; i < CN470_CHANNEL_MASK_SIZE; i++) { + default_channel_mask[i] = 0xFFFF & fsb_mask[i]; + } + + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, CN470_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = CN470_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = CN470_CHANNEL_MASK_SIZE; + + // set bands for CN470 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = CN470_MAX_NB_BANDS; + + // set bandwidths available in CN470 spectrum + phy_params.bandwidths.table = (void *) bandwidths_CN470; + phy_params.bandwidths.size = 6; + + // set data rates available in CN470 spectrum + phy_params.datarates.table = (void *) datarates_CN470; + phy_params.datarates.size = 6; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_CN470; + phy_params.payloads.size = 6; + phy_params.payloads_with_repeater.table = (void *)max_payloads_with_repeater_CN470; + phy_params.payloads_with_repeater.size = 6; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = CN470_DUTY_CYCLE_ENABLED; + + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = false; + phy_params.cflist_supported = false; + phy_params.dl_channel_req_supported = false; + phy_params.custom_channelplans_supported = false; + + phy_params.default_channel_cnt = CN470_MAX_NB_CHANNELS; + phy_params.max_channel_cnt = CN470_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = 0; + phy_params.min_tx_datarate = CN470_TX_MIN_DATARATE; + phy_params.max_tx_datarate = CN470_TX_MAX_DATARATE; + phy_params.min_rx_datarate = CN470_RX_MIN_DATARATE; + phy_params.max_rx_datarate = CN470_RX_MAX_DATARATE; + phy_params.default_datarate = CN470_DEFAULT_DATARATE; + phy_params.default_max_datarate = CN470_TX_MAX_DATARATE; + phy_params.min_rx1_dr_offset = CN470_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = CN470_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = CN470_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = CN470_MIN_TX_POWER; + phy_params.max_tx_power = CN470_MAX_TX_POWER; + phy_params.default_tx_power = CN470_DEFAULT_TX_POWER; + phy_params.default_max_eirp = CN470_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = CN470_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = CN470_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = CN470_ADR_ACK_DELAY; + phy_params.max_rx_window = CN470_MAX_RX_WINDOW; + phy_params.recv_delay1 = CN470_RECEIVE_DELAY1; + phy_params.recv_delay2 = CN470_RECEIVE_DELAY2; + + phy_params.join_accept_delay1 = CN470_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = CN470_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = CN470_MAX_FCNT_GAP; + phy_params.ack_timeout = CN470_ACKTIMEOUT; + phy_params.ack_timeout_rnd = CN470_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = CN470_RX_WND_2_DR; + phy_params.rx_window2_frequency = CN470_RX_WND_2_FREQ; +} + +LoRaPHYCN470::~LoRaPHYCN470() +{ +} + +lorawan_status_t LoRaPHYCN470::set_next_channel(channel_selection_params_t *params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff) +{ + uint8_t channel_count = 0; + uint8_t delay_tx = 0; + + uint8_t enabled_channels[CN470_MAX_NB_CHANNELS] = {0}; + + lorawan_time_t next_tx_delay = 0; + band_t *band_table = (band_t *) phy_params.bands.table; + + if (num_active_channels(phy_params.channels.mask, 0, + phy_params.channels.mask_size) == 0) { + + // Reactivate default channels + copy_channel_mask(phy_params.channels.mask, + phy_params.channels.default_mask, + phy_params.channels.mask_size); + } + + if (params->aggregate_timeoff + <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregate_timeoff = 0; + + // Update bands Time OFF + next_tx_delay = update_band_timeoff(params->joined, + params->dc_enabled, + band_table, phy_params.bands.size); + + // Search how many channels are enabled + channel_count = enabled_channel_count(params->current_datarate, + phy_params.channels.mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + next_tx_delay = params->aggregate_timeoff - + _lora_time->get_elapsed_time(params->last_aggregate_tx_time); + } + + if (channel_count > 0) { + // We found a valid channel + *channel = enabled_channels[get_random(0, channel_count - 1)]; + *time = 0; + return LORAWAN_STATUS_OK; + } + + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = next_tx_delay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; +} + +bool LoRaPHYCN470::rx_config(rx_config_params_t *config) +{ + int8_t dr = config->datarate; + uint8_t max_payload = 0; + int8_t phy_dr = 0; + uint32_t frequency = config->frequency; + + _radio->lock(); + + if (_radio->get_status() != RF_IDLE) { + _radio->unlock(); + return false; + } + + _radio->unlock(); + + if (config->rx_slot == RX_SLOT_WIN_1) { + // Apply window 1 frequency + frequency = CN470_FIRST_RX1_CHANNEL + (config->channel % 48) * CN470_STEPWIDTH_RX1_CHANNEL; + // Caller may print the frequency to log so update it to match actual frequency + config->frequency = frequency; + } + + // Read the physical datarate from the datarates table + phy_dr = datarates_CN470[dr]; + + _radio->lock(); + + _radio->set_channel(frequency); + + // Radio configuration + _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, + MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, + config->window_timeout, false, 0, false, 0, 0, true, + config->is_rx_continuous); + + _radio->unlock(); + + if (config->is_repeater_supported == true) { + max_payload = max_payloads_with_repeater_CN470[dr]; + } else { + max_payload = max_payloads_CN470[dr]; + } + + _radio->lock(); + _radio->set_max_payload_length(MODEM_LORA, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + _radio->unlock(); + + return true; +} + +bool LoRaPHYCN470::tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa) +{ + int8_t phy_dr = datarates_CN470[config->datarate]; + + if (config->tx_power > bands[channels[config->channel].band].max_tx_pwr) { + config->tx_power = bands[channels[config->channel].band].max_tx_pwr; + } + + int8_t phy_tx_power = 0; + + // Calculate physical TX power + phy_tx_power = compute_tx_power(config->tx_power, config->max_eirp, + config->antenna_gain); + + // acquire lock to radio + _radio->lock(); + + _radio->set_channel(channels[config->channel].frequency); + + _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, 0, phy_dr, 1, + MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, false, true, + 0, 0, false, 3000); + // Setup maximum payload lenght of the radio driver + _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); + + // Get the time-on-air of the next tx frame + *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); + + // release lock to radio + _radio->unlock(); + + *tx_power = config->tx_power; + + return true; +} + +uint8_t LoRaPHYCN470::link_ADR_request(adr_req_params_t *params, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, + uint8_t *nb_bytes_parsed) +{ + uint8_t status = 0x07; + link_adr_params_t adr_settings; + uint8_t next_index = 0; + uint8_t bytes_processed = 0; + uint16_t temp_channel_masks[CN470_CHANNEL_MASK_SIZE] = {0, 0, 0, 0, 0, 0}; + + verify_adr_params_t verify_params; + + // Initialize local copy of channels mask + copy_channel_mask(temp_channel_masks, channel_mask, CN470_CHANNEL_MASK_SIZE); + + while (bytes_processed < params->payload_size && + params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { + + // Get ADR request parameters + next_index = parse_link_ADR_req(&(params->payload[bytes_processed]), + params->payload_size, + &adr_settings); + + if (next_index == 0) { + bytes_processed = 0; + // break loop, malformed packet + break; + } + + // Update bytes processed + bytes_processed += next_index; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (adr_settings.ch_mask_ctrl == 6) { + + // Enable all 125 kHz channels + for (uint8_t i = 0; i < CN470_CHANNEL_MASK_SIZE; i++) { + temp_channel_masks[i] = 0xFFFF; + } + + } else if (adr_settings.ch_mask_ctrl == 7) { + + status &= 0xFE; // Channel mask KO + + } else { + + for (uint8_t i = 0; i < 16; i++) { + + if (((adr_settings.channel_mask & (1 << i)) != 0) && + (channels[adr_settings.ch_mask_ctrl * 16 + i].frequency == 0)) { + // Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + + temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; + } + } + + if (bytes_processed == 0) { + *nb_bytes_parsed = 0; + return status; + } + + verify_params.status = status; + verify_params.adr_enabled = params->adr_enabled; + verify_params.datarate = adr_settings.datarate; + verify_params.tx_power = adr_settings.tx_power; + verify_params.nb_rep = adr_settings.nb_rep; + verify_params.current_datarate = params->current_datarate; + verify_params.current_tx_power = params->current_tx_power; + verify_params.current_nb_rep = params->current_nb_trans; + verify_params.channel_mask = temp_channel_masks; + + + // Verify the parameters and update, if necessary + status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, + &adr_settings.tx_power, &adr_settings.nb_rep); + + // Update channelsMask if everything is correct + if (status == 0x07) { + // Copy Mask + copy_channel_mask(channel_mask, temp_channel_masks, CN470_CHANNEL_MASK_SIZE); + } + + // Update status variables + *dr_out = adr_settings.datarate; + *tx_power_out = adr_settings.tx_power; + *nb_rep_out = adr_settings.nb_rep; + *nb_bytes_parsed = bytes_processed; + + return status; +} + +uint8_t LoRaPHYCN470::accept_rx_param_setup_req(rx_param_setup_req_t *params) +{ + uint8_t status = 0x07; + uint32_t freq = params->frequency; + + // acquire radio lock + _radio->lock(); + + if ((_radio->check_rf_frequency(freq) == false) + || (freq < CN470_FIRST_RX1_CHANNEL) + || (freq > CN470_LAST_RX1_CHANNEL) + || (((freq - (uint32_t) CN470_FIRST_RX1_CHANNEL) % (uint32_t) CN470_STEPWIDTH_RX1_CHANNEL) != 0)) { + + status &= 0xFE; // Channel frequency KO + } + + // release radio lock + _radio->unlock(); + + // Verify datarate + if (val_in_range(params->datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE) == 0) { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if (val_in_range(params->dr_offset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET) == 0) { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; +} diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.h b/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.h new file mode 100644 index 0000000..81d07a2 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYCN470.h @@ -0,0 +1,100 @@ +/** + * @file LoRaPHYCN470.h + * + * @brief Implements LoRaPHY for Chinese 470 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_CN470_H_ +#define MBED_OS_LORAPHY_CN470_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +// Definitions +/*! + * LoRaMac maximum number of channels + */ +#define CN470_MAX_NB_CHANNELS 96 + +/*! + * LoRaMac maximum number of bands + */ +#define CN470_MAX_NB_BANDS 1 + + +#define CN470_CHANNEL_MASK_SIZE 6 + + +class LoRaPHYCN470 : public LoRaPHY { + +public: + + LoRaPHYCN470(); + virtual ~LoRaPHYCN470(); + + virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff); + + virtual bool rx_config(rx_config_params_t *config); + + virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa); + + virtual uint8_t link_ADR_request(adr_req_params_t *params, int8_t *dr_out, + int8_t *tx_power_out, uint8_t *nb_rep_out, + uint8_t *nb_bytes_parsed); + + virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); + +private: + + /*! + * LoRaMAC channels + */ + channel_params_t channels[CN470_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[CN470_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[CN470_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[CN470_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_CN470_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.cpp new file mode 100644 index 0000000..d19e95e --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.cpp @@ -0,0 +1,321 @@ +/** + * @file LoRaPHYCN779.cpp + * + * @brief Implements LoRaPHY for Chinese 779 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYCN779.h" +#include "lora_phy_ds.h" + +/*! + * Number of default channels + */ +#define CN779_NUMB_DEFAULT_CHANNELS 3 + +/*! + * Number of channels to apply for the CF list + */ +#define CN779_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define CN779_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define CN779_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define CN779_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define CN779_RX_MAX_DATARATE DR_7 + +#define CN779_DEFAULT_MAX_DATARATE DR_5 + +/*! + * Default datarate used by the node + */ +#define CN779_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define CN779_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define CN779_MAX_RX1_DR_OFFSET 5 + +/*! + * Default Rx1 receive datarate offset + */ +#define CN779_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define CN779_MIN_TX_POWER TX_POWER_5 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define CN779_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define CN779_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define CN779_DEFAULT_MAX_EIRP 12.15f + +/*! + * Default antenna gain + */ +#define CN779_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define CN779_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define CN779_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define CN779_DUTY_CYCLE_ENABLED 1 + +/*! + * Maximum RX window duration + */ +#define CN779_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define CN779_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define CN779_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define CN779_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define CN779_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define CN779_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define CN779_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define CN779_ACK_TIMEOUT_RND 1000 + +/*! + * Verification of default datarate + */ +#if ( CN779_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define CN779_RX_WND_2_FREQ 786000000 + +/*! + * Second reception window channel datarate definition. + */ +#define CN779_RX_WND_2_DR DR_0 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t CN779_BAND0 = {100, CN779_MAX_TX_POWER, 0, 0, 0, 779500000, 786500000}; // 1.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t CN779_LC1 = {779500000, 0, { ((DR_5 << 4) | DR_0) }, 0}; +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t CN779_LC2 = {779700000, 0, { ((DR_5 << 4) | DR_0) }, 0}; + +/*! + * LoRaMac default channel 3 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t CN779_LC3 = {779900000, 0, { ((DR_5 << 4) | DR_0) }, 0}; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define CN779_JOIN_CHANNELS (uint16_t) (LC(1) | LC(2) | LC(3)) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_CN779[] = {12, 11, 10, 9, 8, 7, 7, 50}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_CN779[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_CN779[] = {51, 51, 51, 115, 242, 242, 242, 242}; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater_CN779[] = {51, 51, 51, 115, 222, 222, 222, 222}; + + +LoRaPHYCN779::LoRaPHYCN779() +{ + bands[0] = CN779_BAND0; + + // Channels + channels[0] = CN779_LC1; + channels[0].band = 0; + channels[1] = CN779_LC2; + channels[1].band = 0; + channels[2] = CN779_LC3; + channels[2].band = 0; + + // Initialize the channels default mask + default_channel_mask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, CN779_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = CN779_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = CN779_CHANNEL_MASK_SIZE; + + // set bands for CN779 spectrum + phy_params.bands.table = bands; + phy_params.bands.size = CN779_MAX_NB_BANDS; + + // set bandwidths available in CN779 spectrum + phy_params.bandwidths.table = (void *) bandwidths_CN779; + phy_params.bandwidths.size = 8; + + // set data rates available in CN779 spectrum + phy_params.datarates.table = (void *) datarates_CN779; + phy_params.datarates.size = 8; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_CN779; + phy_params.payloads.size = 8; + phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_CN779; + phy_params.payloads_with_repeater.size = 8; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = CN779_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = true; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = CN779_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = CN779_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = CN779_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = CN779_TX_MIN_DATARATE; + phy_params.max_tx_datarate = CN779_TX_MAX_DATARATE; + phy_params.min_rx_datarate = CN779_RX_MIN_DATARATE; + phy_params.max_rx_datarate = CN779_RX_MAX_DATARATE; + phy_params.default_datarate = CN779_DEFAULT_DATARATE; + phy_params.default_max_datarate = CN779_DEFAULT_MAX_DATARATE; + phy_params.min_rx1_dr_offset = CN779_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = CN779_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = CN779_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = CN779_MIN_TX_POWER; + phy_params.max_tx_power = CN779_MAX_TX_POWER; + phy_params.default_tx_power = CN779_DEFAULT_TX_POWER; + phy_params.default_max_eirp = CN779_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = CN779_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = CN779_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = CN779_ADR_ACK_DELAY; + phy_params.max_rx_window = CN779_MAX_RX_WINDOW; + phy_params.recv_delay1 = CN779_RECEIVE_DELAY1; + phy_params.recv_delay2 = CN779_RECEIVE_DELAY2; + phy_params.join_channel_mask = CN779_JOIN_CHANNELS; + phy_params.join_accept_delay1 = CN779_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = CN779_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = CN779_MAX_FCNT_GAP; + phy_params.ack_timeout = CN779_ACKTIMEOUT; + phy_params.ack_timeout_rnd = CN779_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = CN779_RX_WND_2_DR; + phy_params.rx_window2_frequency = CN779_RX_WND_2_FREQ; +} + +LoRaPHYCN779::~LoRaPHYCN779() +{ +} + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.h b/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.h new file mode 100644 index 0000000..2531a89 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYCN779.h @@ -0,0 +1,76 @@ +/** + * @file LoRaPHYCN779.h + * + * @brief Implements LoRaPHY for Chinese 779 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_CN779_H_ +#define MBED_OS_LORAPHY_CN779_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +#define CN779_MAX_NB_CHANNELS 16 + +#define CN779_MAX_NB_BANDS 1 + +#define CN779_CHANNEL_MASK_SIZE 1 + + +class LoRaPHYCN779 : public LoRaPHY { + +public: + + LoRaPHYCN779(); + virtual ~LoRaPHYCN779(); + +private: + /*! + * LoRaMAC channels + */ + channel_params_t channels[CN779_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[CN779_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[CN779_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[CN779_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_CN779_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.cpp new file mode 100644 index 0000000..50d60ff --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.cpp @@ -0,0 +1,321 @@ +/** + * @file LoRaPHYEU433.cpp + * + * @brief Implements LoRaPHY for European 433 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYEU433.h" +#include "lora_phy_ds.h" + +/*! + * Number of default channels + */ +#define EU433_NUMB_DEFAULT_CHANNELS 3 + +/*! + * Number of channels to apply for the CF list + */ +#define EU433_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define EU433_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define EU433_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define EU433_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define EU433_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define EU433_DEFAULT_DATARATE DR_0 + +#define EU433_DEFAULT_MAX_DATARATE DR_5 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define EU433_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define EU433_MAX_RX1_DR_OFFSET 5 + +/*! + * Default Rx1 receive datarate offset + */ +#define EU433_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define EU433_MIN_TX_POWER TX_POWER_5 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define EU433_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define EU433_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define EU433_DEFAULT_MAX_EIRP 12.15f + +/*! + * Default antenna gain + */ +#define EU433_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define EU433_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define EU433_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define EU433_DUTY_CYCLE_ENABLED 1 + +/*! + * Maximum RX window duration + */ +#define EU433_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define EU433_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define EU433_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define EU433_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define EU433_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define EU433_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define EU433_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define EU433_ACK_TIMEOUT_RND 1000 + +/*! + * Verification of default datarate + */ +#if ( EU433_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define EU433_RX_WND_2_FREQ 434665000 + +/*! + * Second reception window channel datarate definition. + */ +#define EU433_RX_WND_2_DR DR_0 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU433_BAND0 = {100, EU433_MAX_TX_POWER, 0, 0, 0, 433175000, 434665000}; // 1.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU433_LC1 = {433175000, 0, { ((DR_5 << 4) | DR_0) }, 0}; + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU433_LC2 = {433375000, 0, { ((DR_5 << 4) | DR_0) }, 0}; + +/*! + * LoRaMac default channel 3 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU433_LC3 = {433575000, 0, { ((DR_5 << 4) | DR_0) }, 0}; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define EU433_JOIN_CHANNELS (uint16_t) (LC(1) | LC(2) | LC(3)) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_EU433[] = {12, 11, 10, 9, 8, 7, 7, 50}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_EU433[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_EU433[] = {51, 51, 51, 115, 242, 242, 242, 242}; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater_EU433[] = {51, 51, 51, 115, 222, 222, 222, 222}; + + +LoRaPHYEU433::LoRaPHYEU433() +{ + bands[0] = EU433_BAND0; + + // Channels + channels[0] = EU433_LC1; + channels[0].band = 0; + channels[1] = EU433_LC2; + channels[1].band = 0; + channels[2] = EU433_LC3; + channels[2].band = 0; + + // Initialize the channels default mask + default_channel_mask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, EU433_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = EU433_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = EU433_CHANNEL_MASK_SIZE; + + // set bands for EU433 spectrum + phy_params.bands.table = bands; + phy_params.bands.size = EU433_MAX_NB_BANDS; + + // set bandwidths available in EU433 spectrum + phy_params.bandwidths.table = (void *) bandwidths_EU433; + phy_params.bandwidths.size = 8; + + // set data rates available in EU433 spectrum + phy_params.datarates.table = (void *) datarates_EU433; + phy_params.datarates.size = 8; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_EU433; + phy_params.payloads.size = 8; + phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_EU433; + phy_params.payloads_with_repeater.size = 8; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = EU433_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = true; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = EU433_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = EU433_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = EU433_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = EU433_TX_MIN_DATARATE; + phy_params.max_tx_datarate = EU433_TX_MAX_DATARATE; + phy_params.min_rx_datarate = EU433_RX_MIN_DATARATE; + phy_params.max_rx_datarate = EU433_RX_MAX_DATARATE; + phy_params.default_datarate = EU433_DEFAULT_DATARATE; + phy_params.default_max_datarate = EU433_DEFAULT_MAX_DATARATE; + phy_params.min_rx1_dr_offset = EU433_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = EU433_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = EU433_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = EU433_MIN_TX_POWER; + phy_params.max_tx_power = EU433_MAX_TX_POWER; + phy_params.default_tx_power = EU433_DEFAULT_TX_POWER; + phy_params.default_max_eirp = EU433_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = EU433_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = EU433_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = EU433_ADR_ACK_DELAY; + phy_params.max_rx_window = EU433_MAX_RX_WINDOW; + phy_params.recv_delay1 = EU433_RECEIVE_DELAY1; + phy_params.recv_delay2 = EU433_RECEIVE_DELAY2; + phy_params.join_channel_mask = EU433_JOIN_CHANNELS; + phy_params.join_accept_delay1 = EU433_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = EU433_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = EU433_MAX_FCNT_GAP; + phy_params.ack_timeout = EU433_ACKTIMEOUT; + phy_params.ack_timeout_rnd = EU433_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = EU433_RX_WND_2_DR; + phy_params.rx_window2_frequency = EU433_RX_WND_2_FREQ; +} + +LoRaPHYEU433::~LoRaPHYEU433() +{ +} diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.h b/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.h new file mode 100644 index 0000000..81417d9 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYEU433.h @@ -0,0 +1,82 @@ +/** + * @file LoRaPHYEU433.h + * + * @brief Implements LoRaPHY for European 433 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_EU433_H_ +#define MBED_OS_LORAPHY_EU433_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define EU433_MAX_NB_CHANNELS 16 + +/*! + * LoRaMac maximum number of bands + */ +#define EU433_MAX_NB_BANDS 1 + +#define EU433_CHANNEL_MASK_SIZE 1 + + +class LoRaPHYEU433 : public LoRaPHY { + +public: + + LoRaPHYEU433(); + virtual ~LoRaPHYEU433(); + +private: + /*! + * LoRaMAC channels + */ + channel_params_t channels[EU433_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[EU433_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[EU433_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[EU433_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_EU433_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.cpp new file mode 100644 index 0000000..ba1301c --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.cpp @@ -0,0 +1,352 @@ +/** + * @file LoRaPHYEU868.cpp + * + * @brief Implements LoRaPHY for European 868 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYEU868.h" +#include "lora_phy_ds.h" + +/*! + * Number of default channels + */ +#define EU868_NUMB_DEFAULT_CHANNELS 3 + +/*! + * Number of channels to apply for the CF list + */ +#define EU868_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define EU868_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define EU868_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define EU868_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define EU868_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define EU868_DEFAULT_DATARATE DR_0 + +#define EU868_DEFAULT_MAX_DATARATE DR_5 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define EU868_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define EU868_MAX_RX1_DR_OFFSET 5 + +/*! + * Default Rx1 receive datarate offset + */ +#define EU868_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define EU868_MIN_TX_POWER TX_POWER_7 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define EU868_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define EU868_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define EU868_DEFAULT_MAX_EIRP 16.0f + +/*! + * Default antenna gain + */ +#define EU868_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define EU868_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define EU868_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define EU868_DUTY_CYCLE_ENABLED 1 + +/*! + * Maximum RX window duration + */ +#define EU868_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define EU868_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define EU868_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define EU868_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define EU868_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define EU868_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define EU868_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define EU868_ACK_TIMEOUT_RND 1000 + +#if ( EU868_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define EU868_RX_WND_2_FREQ 869525000 + +/*! + * Second reception window channel datarate definition. + */ +#define EU868_RX_WND_2_DR DR_0 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND0 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 865000000, 868000000}; // 1.0 % +/*! + * Band 1 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND1 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 868100000, 868600000}; // 1.0 % + +/*! + * Band 2 definition + * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND2 = {1000, EU868_MAX_TX_POWER, 0, 0, 0, 868700000, 869200000}; // 0.1 % + +/*! + * Band 3 definition + * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND3 = {10, EU868_MAX_TX_POWER, 0, 0, 0, 869400000, 869650000}; // 10.0 % + +/*! + * Band 4 definition + * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND4 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 869700000, 870000000}; // 1.0 % + +/*! + * Band 5 definition - It's actually a sub part of Band 2 + * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t EU868_BAND5 = {1000, EU868_MAX_TX_POWER, 0, 0, 0, 863000000, 865000000}; // 0.1 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU868_LC1 = {868100000, 0, { ((DR_5 << 4) | DR_0) }, 1}; + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU868_LC2 = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; + +/*! + * LoRaMac default channel 3 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t EU868_LC3 = {868500000, 0, { ((DR_5 << 4) | DR_0) }, 1}; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define EU868_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_EU868[] = {12, 11, 10, 9, 8, 7, 7, 50}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_EU868[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_EU868[] = {51, 51, 51, 115, 242, 242, 242, 242}; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_repeater_EU868[] = {51, 51, 51, 115, 222, 222, 222, 222}; + +LoRaPHYEU868::LoRaPHYEU868() +{ + bands[0] = EU868_BAND0; + bands[1] = EU868_BAND1; + bands[2] = EU868_BAND2; + bands[3] = EU868_BAND3; + bands[4] = EU868_BAND4; + bands[5] = EU868_BAND5; + + // Default Channels are always enabled, rest will be added later + channels[0] = EU868_LC1; + channels[0].band = 1; + channels[1] = EU868_LC2; + channels[1].band = 1; + channels[2] = EU868_LC3; + channels[2].band = 1; + + // Initialize the channels default mask + default_channel_mask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, 1); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = EU868_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = EU868_CHANNEL_MASK_SIZE; + + // set bands for EU868 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = EU868_MAX_NB_BANDS; + + // set bandwidths available in EU868 spectrum + phy_params.bandwidths.table = (void *) bandwidths_EU868; + phy_params.bandwidths.size = 8; + + // set data rates available in EU868 spectrum + phy_params.datarates.table = (void *) datarates_EU868; + phy_params.datarates.size = 8; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_EU868; + phy_params.payloads.size = 8; + phy_params.payloads_with_repeater.table = (void *) max_payloads_repeater_EU868; + phy_params.payloads_with_repeater.size = 8; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = EU868_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = true; + phy_params.fsk_supported = true; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = EU868_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = EU868_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = EU868_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = EU868_TX_MIN_DATARATE; + phy_params.max_tx_datarate = EU868_TX_MAX_DATARATE; + phy_params.min_rx_datarate = EU868_RX_MIN_DATARATE; + phy_params.max_rx_datarate = EU868_RX_MAX_DATARATE; + phy_params.default_datarate = EU868_DEFAULT_DATARATE; + phy_params.default_max_datarate = EU868_DEFAULT_MAX_DATARATE; + phy_params.min_rx1_dr_offset = EU868_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = EU868_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = EU868_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = EU868_MIN_TX_POWER; + phy_params.max_tx_power = EU868_MAX_TX_POWER; + phy_params.default_tx_power = EU868_DEFAULT_TX_POWER; + phy_params.default_max_eirp = EU868_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = EU868_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = EU868_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = EU868_ADR_ACK_DELAY; + phy_params.max_rx_window = EU868_MAX_RX_WINDOW; + phy_params.recv_delay1 = EU868_RECEIVE_DELAY1; + phy_params.recv_delay2 = EU868_RECEIVE_DELAY2; + phy_params.join_channel_mask = EU868_JOIN_CHANNELS; + phy_params.join_accept_delay1 = EU868_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = EU868_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = EU868_MAX_FCNT_GAP; + phy_params.ack_timeout = EU868_ACKTIMEOUT; + phy_params.ack_timeout_rnd = EU868_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = EU868_RX_WND_2_DR; + phy_params.rx_window2_frequency = EU868_RX_WND_2_FREQ; +} + +LoRaPHYEU868::~LoRaPHYEU868() +{ +} + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.h b/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.h new file mode 100644 index 0000000..b3f8de8 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYEU868.h @@ -0,0 +1,85 @@ +/** + * @file LoRaPHYEU868.h + * + * @brief Implements LoRaPHY for European 868 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_EU868_H_ +#define MBED_OS_LORAPHY_EU868_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define EU868_MAX_NB_CHANNELS 16 + +/*! + * Maximum number of bands + * + * We have broken down EU-868 MHz BAND 2 into two parts. That's why + * total number of sub-bands is 6. + * from 863 MHz to 865 MHz region is part of BAND 2, however + * we call it Band-5 here. Duty cycle limit is 0.1 % in this sub band. + */ +#define EU868_MAX_NB_BANDS 6 + +#define EU868_CHANNEL_MASK_SIZE 1 + +class LoRaPHYEU868 : public LoRaPHY { + +public: + LoRaPHYEU868(); + virtual ~LoRaPHYEU868(); + +private: + /*! + * LoRaMAC channels + */ + channel_params_t channels[EU868_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[EU868_MAX_NB_BANDS]; + + /*! + * LoRaMac channels mask + */ + uint16_t channel_mask[EU868_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[EU868_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY*/ +#endif /* MBED_OS_LORAPHY_EU868_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.cpp new file mode 100644 index 0000000..bdcfcc2 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.cpp @@ -0,0 +1,328 @@ +/** + * @file LoRaPHYIN865.cpp + * + * @brief Implements LoRaPHY for Indian 865 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYIN865.h" +#include "lora_phy_ds.h" + + +/*! + * Number of default channels + */ +#define IN865_NUMB_DEFAULT_CHANNELS 3 + +/*! + * Number of channels to apply for the CF list + */ +#define IN865_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define IN865_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define IN865_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define IN865_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define IN865_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define IN865_DEFAULT_DATARATE DR_0 +#define IN865_DEFAULT_MAX_DATARATE DR_5 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define IN865_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define IN865_MAX_RX1_DR_OFFSET 7 + +/*! + * Default Rx1 receive datarate offset + */ +#define IN865_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define IN865_MIN_TX_POWER TX_POWER_10 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define IN865_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define IN865_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define IN865_DEFAULT_MAX_EIRP 30.0f + +/*! + * Default antenna gain + */ +#define IN865_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define IN865_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define IN865_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define IN865_DUTY_CYCLE_ENABLED 1 + +/*! + * Maximum RX window duration + */ +#define IN865_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define IN865_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define IN865_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define IN865_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define IN865_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define IN865_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define IN865_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define IN865_ACK_TIMEOUT_RND 1000 + +#if ( IN865_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define IN865_RX_WND_2_FREQ 866550000 + +/*! + * Second reception window channel datarate definition. + */ +#define IN865_RX_WND_2_DR DR_2 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t IN865_BAND0 = { 1, IN865_MAX_TX_POWER, 0, 0, 0, 865000000, 867000000 }; // 100.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t IN865_LC1 = { 865062500, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t IN865_LC2 = { 865402500, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac default channel 3 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t IN865_LC3 = { 865985000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define IN865_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_IN865[] = { 12, 11, 10, 9, 8, 7, 0, 50 }; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_IN865[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_IN865[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + +/*! + * Effective datarate offsets for receive window 1. + */ +static const int8_t rx1_dr_offset_IN865[] = { 0, 1, 2, 3, 4, 5, -1, -2 }; + +LoRaPHYIN865::LoRaPHYIN865() +{ + bands[0] = IN865_BAND0; + + // Default Channels are always enabled, rest will be added later + channels[0] = IN865_LC1; + channels[0].band = 0; + channels[1] = IN865_LC2; + channels[1].band = 0; + channels[2] = IN865_LC3; + channels[2].band = 0; + + // Initialize the channels default mask + default_channel_mask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, 1); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = IN865_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = IN865_CHANNEL_MASK_SIZE; + + // set bands for IN865 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = IN865_MAX_NB_BANDS; + + // set bandwidths available in IN865 spectrum + phy_params.bandwidths.table = (void *) bandwidths_IN865; + phy_params.bandwidths.size = 8; + + // set data rates available in IN865 spectrum + phy_params.datarates.table = (void *) datarates_IN865; + phy_params.datarates.size = 8; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_IN865; + phy_params.payloads.size = 8; + phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater; + phy_params.payloads_with_repeater.size = 8; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = IN865_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = true; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = IN865_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = IN865_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = IN865_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = IN865_TX_MIN_DATARATE; + phy_params.max_tx_datarate = IN865_TX_MAX_DATARATE; + phy_params.min_rx_datarate = IN865_RX_MIN_DATARATE; + phy_params.max_rx_datarate = IN865_RX_MAX_DATARATE; + phy_params.default_datarate = IN865_DEFAULT_DATARATE; + phy_params.default_max_datarate = IN865_DEFAULT_MAX_DATARATE; + phy_params.min_rx1_dr_offset = IN865_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = IN865_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = IN865_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = IN865_MIN_TX_POWER; + phy_params.max_tx_power = IN865_MAX_TX_POWER; + phy_params.default_tx_power = IN865_DEFAULT_TX_POWER; + phy_params.default_max_eirp = IN865_DEFAULT_MAX_EIRP; + phy_params.default_antenna_gain = IN865_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = IN865_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = IN865_ADR_ACK_DELAY; + phy_params.max_rx_window = IN865_MAX_RX_WINDOW; + phy_params.recv_delay1 = IN865_RECEIVE_DELAY1; + phy_params.recv_delay2 = IN865_RECEIVE_DELAY2; + phy_params.join_channel_mask = IN865_JOIN_CHANNELS; + phy_params.join_accept_delay1 = IN865_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = IN865_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = IN865_MAX_FCNT_GAP; + phy_params.ack_timeout = IN865_ACKTIMEOUT; + phy_params.ack_timeout_rnd = IN865_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = IN865_RX_WND_2_DR; + phy_params.rx_window2_frequency = IN865_RX_WND_2_FREQ; +} + +LoRaPHYIN865::~LoRaPHYIN865() +{ +} + +uint8_t LoRaPHYIN865::apply_DR_offset(int8_t dr, int8_t dr_offset) +{ + // Apply offset formula + return MIN(DR_5, MAX(DR_0, dr - rx1_dr_offset_IN865[dr_offset])); +} diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.h b/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.h new file mode 100644 index 0000000..d213c2e --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYIN865.h @@ -0,0 +1,84 @@ +/** + * @file LoRaPHYIN865.h + * + * @brief Implements LoRaPHY for Indian 865 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_IN865_H_ +#define MBED_OS_LORAPHY_IN865_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define IN865_MAX_NB_CHANNELS 16 + +/*! + * Maximum number of bands + */ +#define IN865_MAX_NB_BANDS 1 + +#define IN865_CHANNEL_MASK_SIZE 1 + + +class LoRaPHYIN865 : public LoRaPHY { + +public: + + LoRaPHYIN865(); + virtual ~LoRaPHYIN865(); + + virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); + +private: + /*! + * LoRaMAC channels + */ + channel_params_t channels[IN865_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[IN865_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[IN865_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[IN865_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY */ +#endif /* MBED_OS_LORAPHY_IN865_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.cpp new file mode 100644 index 0000000..e5df591 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.cpp @@ -0,0 +1,507 @@ +/** + * @file LoRaPHYKR920.cpp + * + * @brief Implements LoRaPHY for Korean 920 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "LoRaPHYKR920.h" +#include "lora_phy_ds.h" + + +/*! + * Number of default channels + */ +#define KR920_NUMB_DEFAULT_CHANNELS 3 + +/*! + * Number of channels to apply for the CF list + */ +#define KR920_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define KR920_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define KR920_TX_MAX_DATARATE DR_5 + +/*! + * Minimal datarate that can be used by the node + */ +#define KR920_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define KR920_RX_MAX_DATARATE DR_5 + +/*! + * Default datarate used by the node + */ +#define KR920_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define KR920_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define KR920_MAX_RX1_DR_OFFSET 5 + +/*! + * Default Rx1 receive datarate offset + */ +#define KR920_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define KR920_MIN_TX_POWER TX_POWER_7 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define KR920_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define KR920_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP for frequency 920.9 MHz - 921.9 MHz + */ +#define KR920_DEFAULT_MAX_EIRP_LOW 10.0f + +/*! + * Default Max EIRP for frequency 922.1 MHz - 923.3 MHz + */ +#define KR920_DEFAULT_MAX_EIRP_HIGH 14.0f + +/*! + * Default antenna gain + */ +#define KR920_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define KR920_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define KR920_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define KR920_DUTY_CYCLE_ENABLED 0 + +/*! + * Maximum RX window duration + */ +#define KR920_MAX_RX_WINDOW 4000 + +/*! + * Receive delay 1 + */ +#define KR920_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define KR920_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define KR920_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define KR920_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define KR920_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define KR920_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define KR920_ACK_TIMEOUT_RND 1000 + +#if ( KR920_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define KR920_RX_WND_2_FREQ 921900000 + +/*! + * Second reception window channel datarate definition. + */ +#define KR920_RX_WND_2_DR DR_0 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t KR920_BAND0 = { 1, KR920_MAX_TX_POWER, 0, 0, 0 }; // 100.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t KR920_LC1 = { 922100000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t KR920_LC2 = { 922300000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac default channel 3 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +static const channel_params_t KR920_LC3 = { 922500000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define KR920_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + +/*! + * RSSI threshold for a free channel [dBm] + */ +#define KR920_RSSI_FREE_TH -65 + +/*! + * Specifies the time the node performs a carrier sense + */ +#define KR920_CARRIER_SENSE_TIME 6 + +/*! + * Data rates table definition + */ +static const uint8_t datarates_KR920[] = { 12, 11, 10, 9, 8, 7 }; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_KR920[] = { 125000, 125000, 125000, 125000, 125000, 125000 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with and without a repeater. + */ +static const uint8_t max_payloads_KR920[] = { 51, 51, 51, 115, 242, 242 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater_KR920[] = { 51, 51, 51, 115, 222, 222 }; + +LoRaPHYKR920::LoRaPHYKR920() +{ + bands[0] = KR920_BAND0; + + // Channels + channels[0] = KR920_LC1; + channels[0].band = 0; + channels[1] = KR920_LC2; + channels[1].band = 0; + channels[2] = KR920_LC3; + channels[2].band = 0; + + // Initialize the channels default mask + default_channel_mask[0] = LC(1) + LC(2) + LC(3); + // Update the channels mask + copy_channel_mask(channel_mask, default_channel_mask, KR920_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = KR920_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = KR920_CHANNEL_MASK_SIZE; + + // set bands for KR920 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = KR920_MAX_NB_BANDS; + + // set bandwidths available in KR920 spectrum + phy_params.bandwidths.table = (void *) bandwidths_KR920; + phy_params.bandwidths.size = 6; + + // set data rates available in KR920 spectrum + phy_params.datarates.table = (void *) datarates_KR920; + phy_params.datarates.size = 6; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_KR920; + phy_params.payloads.size = 6; + phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_KR920; + phy_params.payloads_with_repeater.size = 6; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = KR920_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = false; + phy_params.cflist_supported = true; + phy_params.dl_channel_req_supported = true; + phy_params.custom_channelplans_supported = true; + phy_params.default_channel_cnt = KR920_NUMB_DEFAULT_CHANNELS; + phy_params.max_channel_cnt = KR920_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = KR920_NUMB_CHANNELS_CF_LIST; + phy_params.min_tx_datarate = KR920_TX_MIN_DATARATE; + phy_params.max_tx_datarate = KR920_TX_MAX_DATARATE; + phy_params.min_rx_datarate = KR920_RX_MIN_DATARATE; + phy_params.max_rx_datarate = KR920_RX_MAX_DATARATE; + phy_params.default_datarate = KR920_DEFAULT_DATARATE; + phy_params.default_max_datarate = KR920_TX_MAX_DATARATE; + phy_params.min_rx1_dr_offset = KR920_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = KR920_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = KR920_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = KR920_MIN_TX_POWER; + phy_params.max_tx_power = KR920_MAX_TX_POWER; + phy_params.default_tx_power = KR920_DEFAULT_TX_POWER; + phy_params.default_max_eirp = KR920_DEFAULT_MAX_EIRP_HIGH; + phy_params.default_antenna_gain = KR920_DEFAULT_ANTENNA_GAIN; + phy_params.adr_ack_limit = KR920_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = KR920_ADR_ACK_DELAY; + phy_params.max_rx_window = KR920_MAX_RX_WINDOW; + phy_params.recv_delay1 = KR920_RECEIVE_DELAY1; + phy_params.recv_delay2 = KR920_RECEIVE_DELAY2; + phy_params.join_channel_mask = KR920_JOIN_CHANNELS; + phy_params.join_accept_delay1 = KR920_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = KR920_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = KR920_MAX_FCNT_GAP; + phy_params.ack_timeout = KR920_ACKTIMEOUT; + phy_params.ack_timeout_rnd = KR920_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = KR920_RX_WND_2_DR; + phy_params.rx_window2_frequency = KR920_RX_WND_2_FREQ; +} + +LoRaPHYKR920::~LoRaPHYKR920() +{ +} + +int8_t LoRaPHYKR920::get_max_eirp(uint32_t freq) +{ + if (freq >= 922100000) {// Limit to 14dBm + return KR920_DEFAULT_MAX_EIRP_HIGH; + } + + // Limit to 10dBm + return KR920_DEFAULT_MAX_EIRP_LOW; +} + + +bool LoRaPHYKR920::verify_frequency_for_band(uint32_t freq, uint8_t band) const +{ + uint32_t tmp_freq = freq; + + _radio->lock(); + + if (_radio->check_rf_frequency(tmp_freq) == false) { + _radio->unlock(); + return false; + } + + _radio->unlock(); + + // Verify if the frequency is valid. The frequency must be in a specified + // range and can be set to specific values. + if ((tmp_freq >= 920900000) && (tmp_freq <= 923300000)) { + // Range ok, check for specific value + tmp_freq -= 920900000; + if ((tmp_freq % 200000) == 0) { + return true; + } + } + + return false; +} + +bool LoRaPHYKR920::tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa) +{ + int8_t phy_dr = datarates_KR920[config->datarate]; + + if (config->tx_power > bands[channels[config->channel].band].max_tx_pwr) { + config->tx_power = bands[channels[config->channel].band].max_tx_pwr; + } + + uint32_t bandwidth = get_bandwidth(config->datarate); + float max_eirp = get_max_eirp(channels[config->channel].frequency); + int8_t phy_tx_power = 0; + + // Take the minimum between the max_eirp and txConfig->MaxEirp. + // The value of txConfig->MaxEirp could have changed during runtime, e.g. due to a MAC command. + max_eirp = MIN(config->max_eirp, max_eirp); + + // Calculate physical TX power + phy_tx_power = compute_tx_power(config->tx_power, max_eirp, config->antenna_gain); + + // Setup the radio frequency + _radio->lock(); + + _radio->set_channel(channels[config->channel].frequency); + + _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, + false, true, 0, 0, false, 3000); + + // Setup maximum payload lenght of the radio driver + _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); + // Get the time-on-air of the next tx frame + *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); + + _radio->unlock(); + + *tx_power = config->tx_power; + return true; +} + +lorawan_status_t LoRaPHYKR920::set_next_channel(channel_selection_params_t *params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeoff) +{ + uint8_t next_channel_idx = 0; + uint8_t nb_enabled_channels = 0; + uint8_t delay_tx = 0; + uint8_t enabled_channels[KR920_MAX_NB_CHANNELS] = {0}; + lorawan_time_t nextTxDelay = 0; + + if (num_active_channels(channel_mask, 0, 1) == 0) { + // Reactivate default channels + channel_mask[0] |= LC(1) + LC(2) + LC(3); + } + + if (params->aggregate_timeoff <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregate_timeoff = 0; + + // Update bands Time OFF + nextTxDelay = update_band_timeoff(params->joined, params->dc_enabled, + bands, KR920_MAX_NB_BANDS); + + // Search how many channels are enabled + nb_enabled_channels = enabled_channel_count(params->current_datarate, + channel_mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + nextTxDelay = params->aggregate_timeoff - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); + } + + if (nb_enabled_channels > 0) { + + for (uint8_t i = 0, j = get_random(0, nb_enabled_channels - 1); + i < KR920_MAX_NB_CHANNELS; i++) { + next_channel_idx = enabled_channels[j]; + j = (j + 1) % nb_enabled_channels; + + // Perform carrier sense for KR920_CARRIER_SENSE_TIME + // If the channel is free, we can stop the LBT mechanism + _radio->lock(); + + if (_radio->perform_carrier_sense(MODEM_LORA, + channels[next_channel_idx].frequency, + KR920_RSSI_FREE_TH, + KR920_CARRIER_SENSE_TIME) == true) { + // Free channel found + *channel = next_channel_idx; + *time = 0; + _radio->unlock(); + return LORAWAN_STATUS_OK; + } + + _radio->unlock(); + } + + return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; + + } else { + + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + + // Datarate not supported by any channel, restore defaults + channel_mask[0] |= LC(1) + LC(2) + LC(3); + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; + } +} + +void LoRaPHYKR920::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) +{ + (void)given_frequency; + + if (params->tx_power > bands[channels[params->channel].band].max_tx_pwr) { + params->tx_power = bands[channels[params->channel].band].max_tx_pwr; + } + + float max_eirp = get_max_eirp(channels[params->channel].frequency); + int8_t phy_tx_power = 0; + uint32_t frequency = channels[params->channel].frequency; + + // Take the minimum between the max_eirp and params->max_eirp. + // The value of params->max_eirp could have changed during runtime, + // e.g. due to a MAC command. + max_eirp = MIN(params->max_eirp, max_eirp); + + // Calculate physical TX power + phy_tx_power = compute_tx_power(params->tx_power, max_eirp, params->antenna_gain); + + _radio->lock(); + _radio->set_tx_continuous_wave(frequency, phy_tx_power, params->timeout); + _radio->unlock(); +} + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.h b/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.h new file mode 100644 index 0000000..ae7af46 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYKR920.h @@ -0,0 +1,99 @@ +/** + * @file LoRaPHYKR920.h + * + * @brief Implements LoRaPHY for Korean 920 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHY_KR920_H_ +#define MBED_OS_LORAPHY_KR920_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define KR920_MAX_NB_CHANNELS 16 + +/*! + * Maximum number of bands + */ +#define KR920_MAX_NB_BANDS 1 + +#define KR920_CHANNEL_MASK_SIZE 1 + + +class LoRaPHYKR920 : public LoRaPHY { + +public: + + LoRaPHYKR920(); + virtual ~LoRaPHYKR920(); + + virtual bool verify_frequency_for_band(uint32_t freq, uint8_t band) const; + + virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa); + + virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, uint8_t *channel, + lorawan_time_t *time, + lorawan_time_t *aggregate_timeOff); + + virtual void set_tx_cont_mode(cw_mode_params_t *continuousWave, + uint32_t frequency = 0); + + +private: + + int8_t get_max_eirp(uint32_t freq); + + /** + * LoRaMAC channels + */ + channel_params_t channels[KR920_MAX_NB_CHANNELS]; + + /** + * LoRaMac bands + */ + band_t bands[KR920_MAX_NB_BANDS]; + + /** + * LoRaMac channel mask + */ + uint16_t channel_mask[KR920_CHANNEL_MASK_SIZE]; + + /** + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[KR920_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY */ +#endif // MBED_OS_LORAPHY_KR920_H_ + diff --git a/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.cpp new file mode 100644 index 0000000..9882b5e --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.cpp @@ -0,0 +1,718 @@ +/** + * @file LoRaPHUS915.cpp + * + * @brief Implements LoRaPHY for US 915 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include "LoRaPHYUS915.h" +#include "lora_phy_ds.h" + + +/*! + * Minimal datarate that can be used by the node + */ +#define US915_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define US915_TX_MAX_DATARATE DR_4 + +/*! + * Minimal datarate that can be used by the node + */ +#define US915_RX_MIN_DATARATE DR_8 + +/*! + * Maximal datarate that can be used by the node + */ +#define US915_RX_MAX_DATARATE DR_13 + +/*! + * Default datarate used by the node + */ +#define US915_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define US915_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define US915_MAX_RX1_DR_OFFSET 3 + +/*! + * Default Rx1 receive datarate offset + */ +#define US915_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define US915_MIN_TX_POWER TX_POWER_10 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define US915_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define US915_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max ERP + */ +#define US915_DEFAULT_MAX_ERP 30.0f + +/*! + * ADR Ack limit + */ +#define US915_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define US915_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define US915_DUTY_CYCLE_ENABLED 0 + +/*! + * Maximum RX window duration + */ +#define US915_MAX_RX_WINDOW 3000 + +/*! + * Receive delay 1 + */ +#define US915_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define US915_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define US915_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define US915_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define US915_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define US915_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define US915_ACK_TIMEOUT_RND 1000 + +/*! + * Second reception window channel frequency definition. + */ +#define US915_RX_WND_2_FREQ 923300000 + +/*! + * Second reception window channel datarate definition. + */ +#define US915_RX_WND_2_DR DR_8 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +static const band_t US915_BAND0 = { 1, US915_MAX_TX_POWER, 0, 0, 0 }; // 100.0 % + +/*! + * Defines the first channel for RX window 1 for US band + */ +#define US915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) + +/*! + * Defines the last channel for RX window 1 for US band + */ +#define US915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define US915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) + +/*! + * Data rates table definition + */ +static const uint8_t datarates_US915[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0}; + +/*! + * Bandwidths table definition in Hz + */ +static const uint32_t bandwidths_US915[] = {125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0}; + +/*! + * Up/Down link data rates offset definition + */ +static const int8_t datarate_offsets_US915[5][4] = { + { DR_10, DR_9, DR_8, DR_8 }, // DR_0 + { DR_11, DR_10, DR_9, DR_8 }, // DR_1 + { DR_12, DR_11, DR_10, DR_9 }, // DR_2 + { DR_13, DR_12, DR_11, DR_10 }, // DR_3 + { DR_13, DR_13, DR_12, DR_11 }, // DR_4 +}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +static const uint8_t max_payloads_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0}; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +static const uint8_t max_payloads_with_repeater_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; + +static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; +static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; + +LoRaPHYUS915::LoRaPHYUS915() +{ + bands[0] = US915_BAND0; + + // Channels + // 125 kHz channels - Upstream + for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++) { + channels[i].frequency = 902300000 + i * 200000; + channels[i].dr_range.value = (DR_3 << 4) | DR_0; + channels[i].band = 0; + } + // 500 kHz channels - Upstream + for (uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++) { + channels[i].frequency = 903000000 + (i - (US915_MAX_NB_CHANNELS - 8)) * 1600000; + channels[i].dr_range.value = (DR_4 << 4) | DR_4; + channels[i].band = 0; + } + + // Fill-up default channel mask and apply FSB mask too + fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, + default_channel_mask, US915_CHANNEL_MASK_SIZE); + + memset(channel_mask, 0, sizeof(channel_mask)); + memset(current_channel_mask, 0, sizeof(current_channel_mask)); + + // Copy channels default mask + copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); + + // current channel masks keep track of the + // channels previously used, i.e., which channels should be avoided in + // next transmission + copy_channel_mask(current_channel_mask, channel_mask, US915_CHANNEL_MASK_SIZE); + + // set default channels + phy_params.channels.channel_list = channels; + phy_params.channels.channel_list_size = US915_MAX_NB_CHANNELS; + phy_params.channels.mask = channel_mask; + phy_params.channels.default_mask = default_channel_mask; + phy_params.channels.mask_size = US915_CHANNEL_MASK_SIZE; + + // set bands for US915 spectrum + phy_params.bands.table = (void *) bands; + phy_params.bands.size = US915_MAX_NB_BANDS; + + // set bandwidths available in US915 spectrum + phy_params.bandwidths.table = (void *) bandwidths_US915; + phy_params.bandwidths.size = 16; + + // set data rates available in US915 spectrum + phy_params.datarates.table = (void *) datarates_US915; + phy_params.datarates.size = 16; + + // set payload sizes with respect to data rates + phy_params.payloads.table = (void *) max_payloads_US915; + phy_params.payloads.size = 16; + phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_US915; + phy_params.payloads_with_repeater.size = 16; + + // dwell time setting + phy_params.ul_dwell_time_setting = 0; + phy_params.dl_dwell_time_setting = 0; + + // set initial and default parameters + phy_params.duty_cycle_enabled = US915_DUTY_CYCLE_ENABLED; + phy_params.accept_tx_param_setup_req = false; + phy_params.fsk_supported = false; + phy_params.cflist_supported = false; + phy_params.dl_channel_req_supported = false; + phy_params.custom_channelplans_supported = false; + phy_params.default_channel_cnt = US915_MAX_NB_CHANNELS; + phy_params.max_channel_cnt = US915_MAX_NB_CHANNELS; + phy_params.cflist_channel_cnt = 0; + phy_params.min_tx_datarate = US915_TX_MIN_DATARATE; + phy_params.max_tx_datarate = US915_TX_MAX_DATARATE; + phy_params.min_rx_datarate = US915_RX_MIN_DATARATE; + phy_params.max_rx_datarate = US915_RX_MAX_DATARATE; + phy_params.default_datarate = US915_DEFAULT_DATARATE; + phy_params.default_max_datarate = US915_TX_MAX_DATARATE; + phy_params.min_rx1_dr_offset = US915_MIN_RX1_DR_OFFSET; + phy_params.max_rx1_dr_offset = US915_MAX_RX1_DR_OFFSET; + phy_params.default_rx1_dr_offset = US915_DEFAULT_RX1_DR_OFFSET; + phy_params.min_tx_power = US915_MIN_TX_POWER; + phy_params.max_tx_power = US915_MAX_TX_POWER; + phy_params.default_tx_power = US915_DEFAULT_TX_POWER; + phy_params.default_max_eirp = 0; + phy_params.default_antenna_gain = 0; + phy_params.adr_ack_limit = US915_ADR_ACK_LIMIT; + phy_params.adr_ack_delay = US915_ADR_ACK_DELAY; + phy_params.max_rx_window = US915_MAX_RX_WINDOW; + phy_params.recv_delay1 = US915_RECEIVE_DELAY1; + phy_params.recv_delay2 = US915_RECEIVE_DELAY2; + + phy_params.join_accept_delay1 = US915_JOIN_ACCEPT_DELAY1; + phy_params.join_accept_delay2 = US915_JOIN_ACCEPT_DELAY2; + phy_params.max_fcnt_gap = US915_MAX_FCNT_GAP; + phy_params.ack_timeout = US915_ACKTIMEOUT; + phy_params.ack_timeout_rnd = US915_ACK_TIMEOUT_RND; + phy_params.rx_window2_datarate = US915_RX_WND_2_DR; + phy_params.rx_window2_frequency = US915_RX_WND_2_FREQ; +} + +LoRaPHYUS915::~LoRaPHYUS915() +{ +} + +int8_t LoRaPHYUS915::limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, + int8_t datarate) +{ + int8_t tx_power_out = tx_power; + + // Limit tx power to the band max + tx_power_out = MAX(tx_power, max_band_tx_power); + + if (datarate == DR_4) { + // Limit tx power to max 26dBm + tx_power_out = MAX(tx_power, TX_POWER_2); + } else { + + if (num_active_channels(channel_mask, 0, 4) < 50) { + // Limit tx power to max 21dBm + tx_power_out = MAX(tx_power, TX_POWER_5); + } + } + + return tx_power_out; +} + +void LoRaPHYUS915::restore_default_channels() +{ + // Copy channels default mask + copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); + + // Update running channel mask + intersect_channel_mask(channel_mask, current_channel_mask, US915_CHANNEL_MASK_SIZE); +} + +bool LoRaPHYUS915::rx_config(rx_config_params_t *config) +{ + int8_t dr = config->datarate; + uint8_t max_payload = 0; + int8_t phy_dr = 0; + uint32_t frequency = config->frequency; + + _radio->lock(); + + if (_radio->get_status() != RF_IDLE) { + + _radio->unlock(); + return false; + + } + + _radio->unlock(); + + // For US915 spectrum, we have 8 Downstream channels, MAC would have + // selected a channel randomly from 72 Upstream channels, that index is + // passed in rx_config_params_t. Based on that channel index, we choose the + // frequency for first RX slot + if (config->rx_slot == RX_SLOT_WIN_1) { + // Apply window 1 frequency + frequency = US915_FIRST_RX1_CHANNEL + (config->channel % 8) * US915_STEPWIDTH_RX1_CHANNEL; + // Caller may print the frequency to log so update it to match actual frequency + config->frequency = frequency; + } + + // Read the physical datarate from the datarates table + phy_dr = datarates_US915[dr]; + + _radio->lock(); + + _radio->set_channel(frequency); + + // Radio configuration + _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, + MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, + config->window_timeout, false, 0, false, 0, 0, true, + config->is_rx_continuous); + _radio->unlock(); + + if (config->is_repeater_supported == true) { + + max_payload = max_payloads_with_repeater_US915[dr]; + + } else { + + max_payload = max_payloads_US915[dr]; + + } + + _radio->lock(); + + _radio->set_max_payload_length(MODEM_LORA, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + + _radio->unlock(); + + return true; +} + +bool LoRaPHYUS915::tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa) +{ + int8_t phy_dr = datarates_US915[config->datarate]; + int8_t tx_power_limited = limit_tx_power(config->tx_power, + bands[channels[config->channel].band].max_tx_pwr, + config->datarate); + + uint32_t bandwidth = get_bandwidth(config->datarate); + int8_t phy_tx_power = 0; + + // Calculate physical TX power + phy_tx_power = compute_tx_power(tx_power_limited, US915_DEFAULT_MAX_ERP, 0); + + _radio->lock(); + + _radio->set_channel(channels[config->channel].frequency); + + _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, + MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, + false, true, 0, 0, false, 3000); + + // Setup maximum payload lenght of the radio driver + _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); + + // Get the time-on-air of the next tx frame + *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); + + _radio->unlock(); + + *tx_power = tx_power_limited; + + return true; +} + +uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t *params, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, uint8_t *nb_bytes_parsed) +{ + uint8_t status = 0x07; + + link_adr_params_t adr_settings; + uint8_t next_idx = 0; + uint8_t bytes_processed = 0; + uint16_t temp_channel_masks[US915_CHANNEL_MASK_SIZE] = {0, 0, 0, 0, 0}; + + verify_adr_params_t verify_params; + + // Initialize local copy of channels mask + copy_channel_mask(temp_channel_masks, channel_mask, US915_CHANNEL_MASK_SIZE); + + while (bytes_processed < params->payload_size && + params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { + next_idx = parse_link_ADR_req(&(params->payload[bytes_processed]), + params->payload_size - bytes_processed, + &adr_settings); + + if (next_idx == 0) { + bytes_processed = 0; + // break loop, malformed packet + break; + } + + // Update bytes processed + bytes_processed += next_idx; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + if (adr_settings.ch_mask_ctrl == 6) { + + // Enable all 125 kHz channels + fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, + US915_CHANNEL_MASK_SIZE - 1); + + // Apply chMask to channels 64 to 71 + temp_channel_masks[4] = adr_settings.channel_mask; + + } else if (adr_settings.ch_mask_ctrl == 7) { + + // Disable all 125 kHz channels + fill_channel_mask_with_value(temp_channel_masks, 0x0000, + US915_CHANNEL_MASK_SIZE - 1); + + // Apply chMask to channels 64 to 71 + temp_channel_masks[4] = adr_settings.channel_mask; + + } else if (adr_settings.ch_mask_ctrl == 5) { + // RFU + status &= 0xFE; // Channel mask KO + + } else { + temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; + } + } + + if (bytes_processed == 0) { + *nb_bytes_parsed = 0; + return status; + } + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if ((adr_settings.datarate < DR_4) && + (num_active_channels(temp_channel_masks, 0, 4) < 2)) { + + status &= 0xFE; // Channel mask KO + + } + + verify_params.status = status; + verify_params.adr_enabled = params->adr_enabled; + verify_params.datarate = adr_settings.datarate; + verify_params.tx_power = adr_settings.tx_power; + verify_params.nb_rep = adr_settings.nb_rep; + verify_params.current_datarate = params->current_datarate; + verify_params.current_tx_power = params->current_tx_power; + verify_params.current_nb_rep = params->current_nb_trans; + verify_params.channel_mask = temp_channel_masks; + + // Verify the parameters and update, if necessary + status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, + &adr_settings.tx_power, &adr_settings.nb_rep); + + // Update channelsMask if everything is correct + if (status == 0x07) { + // Copy Mask + copy_channel_mask(channel_mask, temp_channel_masks, US915_CHANNEL_MASK_SIZE); + + // update running channel mask + intersect_channel_mask(channel_mask, current_channel_mask, + US915_CHANNEL_MASK_SIZE); + } + + // Update status variables + *dr_out = adr_settings.datarate; + *tx_power_out = adr_settings.tx_power; + *nb_rep_out = adr_settings.nb_rep; + *nb_bytes_parsed = bytes_processed; + + return status; +} + +uint8_t LoRaPHYUS915::accept_rx_param_setup_req(rx_param_setup_req_t *params) +{ + uint8_t status = 0x07; + uint32_t freq = params->frequency; + + // Verify radio frequency + if ((_radio->check_rf_frequency(freq) == false) + || (freq < US915_FIRST_RX1_CHANNEL) + || (freq > US915_LAST_RX1_CHANNEL) + || (((freq - (uint32_t) US915_FIRST_RX1_CHANNEL) % (uint32_t) US915_STEPWIDTH_RX1_CHANNEL) != 0)) { + + status &= 0xFE; // Channel frequency KO + + } + + // Verify datarate + if (val_in_range(params->datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE) == 0) { + + status &= 0xFD; // Datarate KO + + } + + if ((val_in_range(params->datarate, DR_5, DR_7)) || (params->datarate > DR_13)) { + + status &= 0xFD; // Datarate KO + + } + + // Verify datarate offset + if (val_in_range(params->dr_offset, US915_MIN_RX1_DR_OFFSET, US915_MAX_RX1_DR_OFFSET) == 0) { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; +} + +int8_t LoRaPHYUS915::get_alternate_DR(uint8_t nb_trials) +{ + int8_t datarate = 0; + + if ((nb_trials & 0x01) == 0x01) { + datarate = DR_4; + } else { + datarate = DR_0; + } + + return datarate; +} + +lorawan_status_t LoRaPHYUS915::set_next_channel(channel_selection_params_t *params, + uint8_t *channel, lorawan_time_t *time, + lorawan_time_t *aggregate_timeOff) +{ + uint8_t nb_enabled_channels = 0; + uint8_t delay_tx = 0; + uint8_t enabled_channels[US915_MAX_NB_CHANNELS] = {0}; + lorawan_time_t next_tx_delay = 0; + + // Count 125kHz channels + if (num_active_channels(current_channel_mask, 0, 4) == 0) { + // If none of the 125 kHz Upstream channel found, + // Reactivate default channels + copy_channel_mask(current_channel_mask, channel_mask, 4); + } + + // Update the 500 kHz channels in the running mask + if ((params->current_datarate >= DR_4) + && (current_channel_mask[4] & 0x00FF) == 0) { + current_channel_mask[4] = channel_mask[4]; + } + + if (params->aggregate_timeoff <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { + // Reset Aggregated time off + *aggregate_timeOff = 0; + + // Update bands Time OFF + next_tx_delay = update_band_timeoff(params->joined, params->dc_enabled, bands, US915_MAX_NB_BANDS); + + // Search how many channels are enabled + nb_enabled_channels = enabled_channel_count(params->current_datarate, + current_channel_mask, + enabled_channels, &delay_tx); + } else { + delay_tx++; + next_tx_delay = params->aggregate_timeoff - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); + } + + if (nb_enabled_channels > 0) { + // We found a valid channel + *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; + // Disable the channel in the mask + disable_channel(current_channel_mask, *channel, US915_MAX_NB_CHANNELS); + + *time = 0; + return LORAWAN_STATUS_OK; + + } else { + + if (delay_tx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = next_tx_delay; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; + } + + // Datarate not supported by any channel + *time = 0; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; + } +} + +void LoRaPHYUS915::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) +{ + (void)given_frequency; + + int8_t tx_power_limited = limit_tx_power(params->tx_power, + bands[channels[params->channel].band].max_tx_pwr, + params->datarate); + int8_t phyTxPower = 0; + uint32_t frequency = channels[params->channel].frequency; + + // Calculate physical TX power + phyTxPower = compute_tx_power(tx_power_limited, US915_DEFAULT_MAX_ERP, 0); + + _radio->lock(); + + _radio->set_tx_continuous_wave(frequency, phyTxPower, params->timeout); + + _radio->unlock(); +} + +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/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.h b/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.h new file mode 100644 index 0000000..1896c4a --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/LoRaPHYUS915.h @@ -0,0 +1,135 @@ +/** + * @file LoRaPHYUS915.h + * + * @brief Implements LoRaPHY for US 915 MHz band + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORAPHYUS_915_H_ +#define MBED_OS_LORAPHYUS_915_H_ + +#if !(DOXYGEN_ONLY) + +#include "LoRaPHY.h" + +/*! + * LoRaMac maximum number of channels + */ +#define US915_MAX_NB_CHANNELS 72 + +/*! + * LoRaMac maximum number of bands + */ +#define US915_MAX_NB_BANDS 1 + +#define US915_CHANNEL_MASK_SIZE 5 + + +class LoRaPHYUS915 : public LoRaPHY { + +public: + + LoRaPHYUS915(); + virtual ~LoRaPHYUS915(); + + virtual void restore_default_channels(); + + virtual bool rx_config(rx_config_params_t *config); + + virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, + lorawan_time_t *tx_toa); + + virtual uint8_t link_ADR_request(adr_req_params_t *params, + int8_t *dr_out, int8_t *tx_power_out, + uint8_t *nb_rep_out, + uint8_t *nb_bytes_parsed); + + virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); + + virtual int8_t get_alternate_DR(uint8_t nb_trials); + + virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, uint8_t *channel, + lorawan_time_t *time, lorawan_time_t *aggregate_timeOff); + + virtual void set_tx_cont_mode(cw_mode_params_t *continuousWave, + uint32_t frequency = 0); + + 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); + + int8_t limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, + int8_t datarate); + + /*! + * LoRaMAC channels + */ + channel_params_t channels[US915_MAX_NB_CHANNELS]; + + /*! + * LoRaMac bands + */ + band_t bands[US915_MAX_NB_BANDS]; + + /*! + * LoRaMac channel mask + */ + uint16_t channel_mask[US915_CHANNEL_MASK_SIZE]; + + /*! + * Previously used channel mask + */ + uint16_t current_channel_mask[US915_CHANNEL_MASK_SIZE]; + + /*! + * LoRaMac default channel mask + */ + uint16_t default_channel_mask[US915_CHANNEL_MASK_SIZE]; +}; + +#endif /* DOXYGEN_ONLY */ +#endif /* MBED_OS_LORAPHY_US915_H_ */ diff --git a/connectivity/lorawan/lorastack/phy/lora_phy_ds.h b/connectivity/lorawan/lorastack/phy/lora_phy_ds.h new file mode 100644 index 0000000..4bd5cff --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/lora_phy_ds.h @@ -0,0 +1,565 @@ +/** + * @file lora_phy_ds.h + * + * @brief Data structures relating to PHY layer + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_OS_LORA_PHY_DATASTRUCTURES_ +#define MBED_OS_LORA_PHY_DATASTRUCTURES_ + +#include "system/lorawan_data_structures.h" + +/*! + * \brief Returns the minimum value between a and b. + * + * \param [in] a The first value. + * \param [in] b The second value. + * \retval minValue The minimum value. + */ +#ifndef MIN +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + +/*! + * \brief Returns the maximum value between a and b + * + * \param [in] a The first value. + * \param [in] b The second value. + * \retval maxValue The maximum value. + */ +#ifndef MAX +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + +/** + * LoRaMac maximum number of channels. + */ +#define LORA_MAX_NB_CHANNELS 16 + +/*! + * Macro to compute bit of a channel index. + */ +#define LC( channelIndex ) ( uint16_t )( 1 << ( channelIndex - 1 ) ) + + + + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP + * AU915 | Max EIRP + * CN470 | Max EIRP + * CN779 | Max EIRP + * EU433 | Max EIRP + * EU868 | Max EIRP + * IN865 | Max EIRP + * KR920 | Max EIRP + * US915 | Max ERP + * US915_HYBRID | Max ERP + */ +#define TX_POWER_0 0 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 2 + * AU915 | Max EIRP - 2 + * CN470 | Max EIRP - 2 + * CN779 | Max EIRP - 2 + * EU433 | Max EIRP - 2 + * EU868 | Max EIRP - 2 + * IN865 | Max EIRP - 2 + * KR920 | Max EIRP - 2 + * US915 | Max ERP - 2 + * US915_HYBRID | Max ERP - 2 + */ +#define TX_POWER_1 1 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 4 + * AU915 | Max EIRP - 4 + * CN470 | Max EIRP - 4 + * CN779 | Max EIRP - 4 + * EU433 | Max EIRP - 4 + * EU868 | Max EIRP - 4 + * IN865 | Max EIRP - 4 + * KR920 | Max EIRP - 4 + * US915 | Max ERP - 4 + * US915_HYBRID | Max ERP - 4 + */ +#define TX_POWER_2 2 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 6 + * AU915 | Max EIRP - 6 + * CN470 | Max EIRP - 6 + * CN779 | Max EIRP - 6 + * EU433 | Max EIRP - 6 + * EU868 | Max EIRP - 6 + * IN865 | Max EIRP - 6 + * KR920 | Max EIRP - 6 + * US915 | Max ERP - 6 + * US915_HYBRID | Max ERP - 6 + */ +#define TX_POWER_3 3 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 8 + * AU915 | Max EIRP - 8 + * CN470 | Max EIRP - 8 + * CN779 | Max EIRP - 8 + * EU433 | Max EIRP - 8 + * EU868 | Max EIRP - 8 + * IN865 | Max EIRP - 8 + * KR920 | Max EIRP - 8 + * US915 | Max ERP - 8 + * US915_HYBRID | Max ERP - 8 + */ +#define TX_POWER_4 4 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 10 + * AU915 | Max EIRP - 10 + * CN470 | Max EIRP - 10 + * CN779 | Max EIRP - 10 + * EU433 | Max EIRP - 10 + * EU868 | Max EIRP - 10 + * IN865 | Max EIRP - 10 + * KR920 | Max EIRP - 10 + * US915 | Max ERP - 10 + * US915_HYBRID | Max ERP - 10 + */ +#define TX_POWER_5 5 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 12 + * AU915 | Max EIRP - 12 + * CN470 | Max EIRP - 12 + * CN779 | - + * EU433 | - + * EU868 | Max EIRP - 12 + * IN865 | Max EIRP - 12 + * KR920 | Max EIRP - 12 + * US915 | Max ERP - 12 + * US915_HYBRID | Max ERP - 12 + */ +#define TX_POWER_6 6 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | Max EIRP - 14 + * AU915 | Max EIRP - 14 + * CN470 | Max EIRP - 14 + * CN779 | - + * EU433 | - + * EU868 | Max EIRP - 14 + * IN865 | Max EIRP - 14 + * KR920 | Max EIRP - 14 + * US915 | Max ERP - 14 + * US915_HYBRID | Max ERP - 14 + */ +#define TX_POWER_7 7 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | - + * AU915 | Max EIRP - 16 + * CN470 | - + * CN779 | - + * EU433 | - + * EU868 | - + * IN865 | Max EIRP - 16 + * KR920 | - + * US915 | Max ERP - 16 + * US915_HYBRID | Max ERP -16 + */ +#define TX_POWER_8 8 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | - + * AU915 | Max EIRP - 18 + * CN470 | - + * CN779 | - + * EU433 | - + * EU868 | - + * IN865 | Max EIRP - 18 + * KR920 | - + * US915 | Max ERP - 16 + * US915_HYBRID | Max ERP - 16 + */ +#define TX_POWER_9 9 + +/*! + * Region | dBM + * ------------ | :-----: + * AS923 | - + * AU915 | Max EIRP - 20 + * CN470 | - + * CN779 | - + * EU433 | - + * EU868 | - + * IN865 | Max EIRP - 20 + * KR920 | - + * US915 | Max ERP - 10 + * US915_HYBRID | Max ERP - 10 + */ +#define TX_POWER_10 10 + +/*! + * RFU + */ +#define TX_POWER_11 11 + +/*! + * RFU + */ +#define TX_POWER_12 12 + +/*! + * RFU + */ +#define TX_POWER_13 13 + +/*! + * RFU + */ +#define TX_POWER_14 14 + +/*! + * RFU + */ +#define TX_POWER_15 15 + +/** + * TX configuration parameters. + */ +typedef struct { + /** + * The TX channel. + */ + uint8_t channel; + /** + * The TX datarate. + */ + int8_t datarate; + /** + * The TX power. + */ + int8_t tx_power; + /** + * The Max EIRP, if applicable. + */ + float max_eirp; + /** + * The antenna gain, if applicable. + */ + float antenna_gain; + /** + * The frame length to set up. + */ + uint16_t pkt_len; +} tx_config_params_t; + +/** + * This structure contains parameters for ADR request coming from + * network server. + */ +typedef struct { + /*! + * A pointer to the payload containing the MAC commands. + */ + const uint8_t *payload; + /*! + * The size of the payload. + */ + uint8_t payload_size; + /*! + * The uplink dwell time. + */ + uint8_t ul_dwell_time; + /*! + * Set to true, if ADR is enabled. + */ + bool adr_enabled; + /*! + * The current datarate. + */ + int8_t current_datarate; + /*! + * The current TX power. + */ + int8_t current_tx_power; + /*! + * The current number of repetitions for obtaining a QOS level set by + * NS (applicable only to unconfirmed messages). + */ + uint8_t current_nb_trans; +} adr_req_params_t; + +/** + * Structure containing data for local ADR settings + */ +typedef struct link_adr_params_s { + /** + * The number of repetitions. + */ + uint8_t nb_rep; + /** + * Datarate. + */ + int8_t datarate; + /** + * TX power. + */ + int8_t tx_power; + /** + * Channels mask control field. + */ + uint8_t ch_mask_ctrl; + /** + * Channels mask field. + */ + uint16_t channel_mask; +} link_adr_params_t; + +/** + * Structure used to store ADR values received from network + * for verification (legality) purposes. + */ +typedef struct verify_adr_params_s { + /*! + * The current status of the AdrLinkRequest. + */ + uint8_t status; + /*! + * Set to true, if ADR is enabled. + */ + bool adr_enabled; + /*! + * The datarate the AdrLinkRequest wants to set. + */ + int8_t datarate; + /*! + * The TX power the AdrLinkRequest wants to set. + */ + int8_t tx_power; + /*! + * The number of repetitions the AdrLinkRequest wants to set. + */ + uint8_t nb_rep; + /*! + * The current datarate the node is using. + */ + int8_t current_datarate; + /*! + * The current TX power the node is using. + */ + int8_t current_tx_power; + /*! + * The current number of repetitions the node is using. + */ + int8_t current_nb_rep; + + /*! + * A pointer to the first element of the channels mask. + */ + uint16_t *channel_mask; +} verify_adr_params_t; + +/** + * Contains rx parameter setup request coming from + * network server. + */ +typedef struct rx_param_setup_req_s { + /** + * The datarate to set up. + */ + int8_t datarate; + /** + * The datarate offset. + */ + int8_t dr_offset; + /** + * The frequency to set up. + */ + uint32_t frequency; +} rx_param_setup_req_t; + +/** + * The parameter structure for the function RegionNextChannel. + */ +typedef struct channel_selection_params_s { + /** + * The aggregated time-off time. + */ + lorawan_time_t aggregate_timeoff; + /** + * The time of the last aggregated TX. + */ + lorawan_time_t last_aggregate_tx_time; + /** + * The current datarate. + */ + int8_t current_datarate; + /** + * Set to true, if the node has already joined a network, otherwise false. + */ + bool joined; + /** + * Set to true, if the duty cycle is enabled, otherwise false. + */ + bool dc_enabled; +} channel_selection_params_t; + +/*! + * The parameter structure for the function RegionContinuousWave. + */ +typedef struct continuous_wave_mode_params_s { + /*! + * The current channel index. + */ + uint8_t channel; + /*! + * The datarate. Used to limit the TX power. + */ + int8_t datarate; + /*! + * The TX power to set up. + */ + int8_t tx_power; + /*! + * The max EIRP, if applicable. + */ + float max_eirp; + /*! + * The antenna gain, if applicable. + */ + float antenna_gain; + /*! + * Specifies the time the radio will stay in CW mode. + */ + uint16_t timeout; +} cw_mode_params_t; + +/*! + * Template for a table + */ +typedef struct { + void *table; + uint8_t size; +} loraphy_table_t; + +/*! + * Contains information regarding channel configuration of + * a given PHY + */ +typedef struct { + uint8_t channel_list_size; + uint8_t mask_size; + uint16_t *mask; + uint16_t *default_mask; + channel_params_t *channel_list; +} loraphy_channels_t; + +/*! + * Global configuration parameters of a given PHY + */ +typedef struct { + bool duty_cycle_enabled; + bool accept_tx_param_setup_req; + bool fsk_supported; + bool cflist_supported; + bool custom_channelplans_supported; + bool dl_channel_req_supported; + + uint8_t default_channel_cnt; + uint8_t cflist_channel_cnt; + uint8_t max_channel_cnt; + uint8_t min_tx_power; + uint8_t max_tx_power; + uint8_t default_tx_power; + uint8_t adr_ack_limit; + uint8_t adr_ack_delay; + + uint8_t min_tx_datarate; + uint8_t max_tx_datarate; + uint8_t min_rx_datarate; + uint8_t max_rx_datarate; + uint8_t default_datarate; + uint8_t default_max_datarate; + uint8_t min_rx1_dr_offset; + uint8_t max_rx1_dr_offset; + uint8_t default_rx1_dr_offset; + uint8_t dwell_limit_datarate; + + uint16_t max_rx_window; + uint16_t recv_delay1; + uint16_t recv_delay2; + uint16_t join_accept_delay1; + uint16_t join_accept_delay2; + uint16_t join_channel_mask; + uint16_t max_fcnt_gap; + uint16_t ack_timeout; + uint16_t ack_timeout_rnd; + + float default_max_eirp; + float default_antenna_gain; + + uint8_t rx_window2_datarate; + uint32_t rx_window2_frequency; + + loraphy_table_t bands; + loraphy_table_t bandwidths; + loraphy_table_t datarates; + loraphy_table_t payloads; + loraphy_table_t payloads_with_repeater; + + loraphy_channels_t channels; + + + unsigned ul_dwell_time_setting : 1; + unsigned dl_dwell_time_setting : 1; + +} loraphy_params_t; + + +#endif /* MBED_OS_LORA_PHY_DATASTRUCTURES_ */ diff --git a/connectivity/lorawan/lorastack/phy/loraphy_target.h b/connectivity/lorawan/lorastack/phy/loraphy_target.h new file mode 100644 index 0000000..cef9be9 --- /dev/null +++ b/connectivity/lorawan/lorastack/phy/loraphy_target.h @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2017, 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. + */ + +#ifndef LORAPHY_TARGET +#define LORAPHY_TARGET + +#ifdef MBED_CONF_LORA_PHY + +#define LORA_REGION_EU868 0x10 +#define LORA_REGION_AS923 0x11 +#define LORA_REGION_AU915 0x12 +#define LORA_REGION_CN470 0x13 +#define LORA_REGION_CN779 0x14 +#define LORA_REGION_EU433 0x15 +#define LORA_REGION_IN865 0x16 +#define LORA_REGION_KR920 0x17 +#define LORA_REGION_US915 0x18 + +//DO NOT USE integer values in mbed_app.json! +//These are defined for backward compatibility and +//Will be DEPRECATED in the future +#define LORA_REGION_0 0x10 +#define LORA_REGION_1 0x11 +#define LORA_REGION_2 0x12 +#define LORA_REGION_3 0x13 +#define LORA_REGION_4 0x14 +#define LORA_REGION_5 0x15 +#define LORA_REGION_6 0x16 +#define LORA_REGION_7 0x17 +#define LORA_REGION_8 0x18 + +//Since 0 would be equal to any undefined value we need to handle this in a other way +#define mbed_lora_concat_(x) LORA_REGION_##x +#define mbed_lora_concat(x) mbed_lora_concat_(x) +#define LORA_REGION mbed_lora_concat(MBED_CONF_LORA_PHY) + +#if LORA_REGION == LORA_REGION_EU868 +#include "lorawan/lorastack/phy/LoRaPHYEU868.h" +#define LoRaPHY_region LoRaPHYEU868 +#elif LORA_REGION == LORA_REGION_AS923 +#include "lorawan/lorastack/phy/LoRaPHYAS923.h" +#define LoRaPHY_region LoRaPHYAS923 +#elif LORA_REGION == LORA_REGION_AU915 +#include "lorawan/lorastack/phy/LoRaPHYAU915.h" +#define LoRaPHY_region LoRaPHYAU915 +#elif LORA_REGION == LORA_REGION_CN470 +#include "lorawan/lorastack/phy/LoRaPHYCN470.h" +#define LoRaPHY_region LoRaPHYCN470 +#elif LORA_REGION == LORA_REGION_CN779 +#include "lorawan/lorastack/phy/LoRaPHYCN779.h" +#define LoRaPHY_region LoRaPHYCN779 +#elif LORA_REGION == LORA_REGION_EU433 +#include "lorawan/lorastack/phy/LoRaPHYEU433.h" +#define LoRaPHY_region LoRaPHYEU433 +#elif LORA_REGION == LORA_REGION_IN865 +#include "lorawan/lorastack/phy/LoRaPHYIN865.h" +#define LoRaPHY_region LoRaPHYIN865 +#elif LORA_REGION == LORA_REGION_KR920 +#include "lorawan/lorastack/phy/LoRaPHYKR920.h" +#define LoRaPHY_region LoRaPHYKR920 +#elif LORA_REGION == LORA_REGION_US915 +#include "lorawan/lorastack/phy/LoRaPHYUS915.h" +#define LoRaPHY_region LoRaPHYUS915 +#else +#error "Invalid region configuration, update mbed_app.json with correct MBED_CONF_LORA_PHY value" +#endif //MBED_CONF_LORA_PHY == VALUE +#else +#error "Must set LoRa PHY layer parameters." +#endif //MBED_CONF_LORA_PHY + +#endif // LORAPHY_TARGET + diff --git a/connectivity/lorawan/lorawan_types.h b/connectivity/lorawan/lorawan_types.h new file mode 100644 index 0000000..324a5bc --- /dev/null +++ b/connectivity/lorawan/lorawan_types.h @@ -0,0 +1,679 @@ +/** + * @file lorawan_types.h + * + * @brief Contains data structures required by LoRaWANBase class. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef MBED_LORAWAN_TYPES_H_ +#define MBED_LORAWAN_TYPES_H_ + +#include "platform/Callback.h" + +/** + * A mask for the network ID. + */ +#define LORAWAN_NETWORK_ID_MASK (uint32_t) 0xFE000000 + +/** + * Option Flags for send(), receive() APIs + * + * Special Notes for UPLINK: + * i) All of the flags are mutually exclusive. + * ii) MSG_MULTICAST_FLAG cannot be used. + */ +#define MSG_UNCONFIRMED_FLAG 0x01 +#define MSG_CONFIRMED_FLAG 0x02 +#define MSG_MULTICAST_FLAG 0x04 +#define MSG_PROPRIETARY_FLAG 0x08 + +/** + * LoRaWAN device classes definition. + * + * LoRaWAN Specification V1.0.2, chapter 2.1. + */ +typedef enum { + /** + * LoRaWAN device class A. + * + * LoRaWAN Specification V1.0.2, chapter 3. + */ + CLASS_A, + /** + * LoRaWAN device class B. + * + * LoRaWAN Specification V1.0.2, chapter 8. + */ + CLASS_B, + /** + * LoRaWAN device class C. + * + * LoRaWAN Specification V1.0.2, chapter 17. + */ + CLASS_C, +} device_class_t; + +/** + * lorawan_status_t contains status codes in + * response to stack operations + */ +typedef enum lorawan_status { + LORAWAN_STATUS_OK = 0, /**< Service started successfully */ + LORAWAN_STATUS_BUSY = -1000, /**< Service not started - LoRaMAC is busy */ + LORAWAN_STATUS_WOULD_BLOCK = -1001, /**< LoRaMAC cannot send at the moment or have nothing to read */ + LORAWAN_STATUS_SERVICE_UNKNOWN = -1002, /**< Service unknown */ + LORAWAN_STATUS_PARAMETER_INVALID = -1003, /**< Service not started - invalid parameter */ + LORAWAN_STATUS_FREQUENCY_INVALID = -1004, /**< Service not started - invalid frequency */ + LORAWAN_STATUS_DATARATE_INVALID = -1005, /**< Service not started - invalid datarate */ + LORAWAN_STATUS_FREQ_AND_DR_INVALID = -1006, /**< Service not started - invalid frequency and datarate */ + LORAWAN_STATUS_NO_NETWORK_JOINED = -1009, /**< Service not started - the device is not in a LoRaWAN */ + LORAWAN_STATUS_LENGTH_ERROR = -1010, /**< Service not started - payload lenght error */ + LORAWAN_STATUS_DEVICE_OFF = -1011, /**< Service not started - the device is switched off */ + LORAWAN_STATUS_NOT_INITIALIZED = -1012, /**< Service not started - stack not initialized */ + LORAWAN_STATUS_UNSUPPORTED = -1013, /**< Service not supported */ + LORAWAN_STATUS_CRYPTO_FAIL = -1014, /**< Service not started - crypto failure */ + LORAWAN_STATUS_PORT_INVALID = -1015, /**< Invalid port */ + LORAWAN_STATUS_CONNECT_IN_PROGRESS = -1016, /**< Services started - Connection in progress */ + LORAWAN_STATUS_NO_ACTIVE_SESSIONS = -1017, /**< Services not started - No active session */ + LORAWAN_STATUS_IDLE = -1018, /**< Services started - Idle at the moment */ + LORAWAN_STATUS_NO_OP = -1019, /**< Cannot perform requested operation */ + LORAWAN_STATUS_DUTYCYCLE_RESTRICTED = -1020, /**< Transmission will continue after duty cycle backoff*/ + LORAWAN_STATUS_NO_CHANNEL_FOUND = -1021, /**< None of the channels is enabled at the moment*/ + LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND = -1022, /**< None of the enabled channels is ready for another TX (duty cycle limited)*/ + LORAWAN_STATUS_METADATA_NOT_AVAILABLE = -1023, /**< Meta-data after an RX or TX is stale*/ + LORAWAN_STATUS_ALREADY_CONNECTED = -1024 /**< The device has already joined a network*/ +} lorawan_status_t; + +/** The lorawan_connect_otaa structure. + * + * A structure representing the LoRaWAN Over The Air Activation + * parameters. + */ +typedef struct { + /** End-device identifier + * + * LoRaWAN Specification V1.0.2, chapter 6.2.1 + */ + uint8_t *dev_eui; + /** Application identifier + * + * LoRaWAN Specification V1.0.2, chapter 6.1.2 + */ + uint8_t *app_eui; + /** AES-128 application key + * + * LoRaWAN Specification V1.0.2, chapter 6.2.2 + */ + uint8_t *app_key; + /** Join request trials + * + * Number of trials for the join request. + */ + uint8_t nb_trials; +} lorawan_connect_otaa_t; + +/** The lorawan_connect_abp structure. + * + * A structure representing the LoRaWAN Activation By Personalization + * parameters. + */ +typedef struct { + /** Network identifier + * + * LoRaWAN Specification V1.0.2, chapter 6.1.1 + */ + uint32_t nwk_id; + /** End-device address + * + * LoRaWAN Specification V1.0.2, chapter 6.1.1 + */ + uint32_t dev_addr; + /** Network session key + * + * LoRaWAN Specification V1.0.2, chapter 6.1.3 + */ + uint8_t *nwk_skey; + /** Application session key + * + * LoRaWAN Specification V1.0.2, chapter 6.1.4 + */ + uint8_t *app_skey; +} lorawan_connect_abp_t; + +/** lorawan_connect_t structure + * + * A structure representing the parameters for different connections. + */ +typedef struct lorawan_connect { + /** + * Select the connection type, either LORAWAN_CONNECTION_OTAA + * or LORAWAN_CONNECTION_ABP. + */ + uint8_t connect_type; + + union { + /** + * Join the network using OTA + */ + lorawan_connect_otaa_t otaa; + /** + * Authentication by personalization + */ + lorawan_connect_abp_t abp; + } connection_u; + +} lorawan_connect_t; + +/** + * Events needed to announce stack operation results. + * + * CONNECTED - When the connection is complete + * DISCONNECTED - When the protocol is shut down in response to disconnect() + * TX_DONE - When a packet is sent + * TX_TIMEOUT, - When stack was unable to send packet in TX window + * TX_ERROR, - A general TX error + * CRYPTO_ERROR, - A crypto error indicating wrong keys + * TX_SCHEDULING_ERROR, - When stack is unable to schedule packet + * RX_DONE, - When there is something to receive + * RX_TIMEOUT, - Not yet mapped + * RX_ERROR - A general RX error + * JOIN_FAILURE - When all Joining retries are exhausted + * UPLINK_REQUIRED - Stack indicates application that some uplink needed + * AUTOMATIC_UPLINK_ERROR - Stack tried automatically send uplink but some error occurred. + * Application should initiate uplink as soon as possible. + * + */ +typedef enum lora_events { + CONNECTED = 0, + DISCONNECTED, + TX_DONE, + TX_TIMEOUT, + TX_ERROR, + CRYPTO_ERROR, + TX_CRYPTO_ERROR = CRYPTO_ERROR, //keeping this for backward compatibility + TX_SCHEDULING_ERROR, + RX_DONE, + RX_TIMEOUT, + RX_ERROR, + JOIN_FAILURE, + UPLINK_REQUIRED, + AUTOMATIC_UPLINK_ERROR, +} lorawan_event_t; + +/** + * Stack level callback functions + * + * 'lorawan_app_callbacks_t' is a structure that holds pointers to the application + * provided methods which are needed to be called in response to certain + * requests. The structure is default constructed to set all pointers to NULL. + * So if the user does not provide the pointer, a response will not be posted. + * However, the 'lorawan_events' callback is mandatory to be provided as it + * contains essential events. + * + * A link check request could be sent whenever the device tries to send a + * message and if the network server responds with a link check response, + * the stack notifies the application be calling the appropriate method set using + * 'link_check_resp' callback. The result is thus transported to the application + * via callback function provided. + * + * 'battery_level' callback goes in the down direction, i.e., it informs + * the stack about the battery level by calling a function provided + * by the upper layers. + */ +typedef struct { + /** + * Mandatory. Event Callback must be provided + */ + mbed::Callback events; + + /** + * This callback is optional + * + * The first parameter to the callback function is the demodulation margin, and the second + * parameter is the number of gateways that successfully received the last request. + */ + mbed::Callback link_check_resp; + + /** + * This callback is optional. If the callback is not set, the stack returns 255 to gateway. + * + * Battery level return value must follow the specification + * for DevStatusAns MAC command: + * + * 0 The end-device is connected to an external power source + * 1 - 254 The battery level, 1 being at minimum and 254 being at maximum + * 255 The end-device was not able to measure the battery level. + */ + mbed::Callback battery_level; +} lorawan_app_callbacks_t; + +/** + * DO NOT MODIFY, WILL BREAK THE API! + * + * Structure containing a given data rate range. + */ +typedef union { + /** + * Byte-access to the bits. + */ + uint8_t value; + /** + * The structure to store the minimum and the maximum datarate. + */ + struct fields_s { + /** + * The minimum data rate. + * + * LoRaWAN Regional Parameters V1.0.2rB. + * + * The allowed ranges are region-specific. + * Please refer to \ref DR_0 to \ref DR_15 for details. + */ + uint8_t min : 4; + /** + * The maximum data rate. + * + * LoRaWAN Regional Parameters V1.0.2rB. + * + * The allowed ranges are region-specific. + * Please refer to \ref DR_0 to \ref DR_15 for details. + */ + uint8_t max : 4; + } fields; +} dr_range_t; + +/** + * DO NOT MODIFY, WILL BREAK THE API! + * + * LoRaMAC channel definition. + */ +typedef struct { + /** + * The frequency in Hz. + */ + uint32_t frequency; + /** + * The alternative frequency for RX window 1. + */ + uint32_t rx1_frequency; + /** + * The data rate definition. + */ + dr_range_t dr_range; + /** + * The band index. + */ + uint8_t band; +} channel_params_t; + +/** + * DO NOT MODIFY, WILL BREAK THE API! + * + * Structure to hold parameters for a LoRa channel. + */ +typedef struct lora_channels_s { + uint8_t id; + channel_params_t ch_param; +} loramac_channel_t; + +/** + * DO NOT MODIFY, WILL BREAK THE API! + * + * This data structures contains LoRaWAN channel plan, i.e., a pointer to a + * list of channels and the total number of channels included in the plan. + */ +typedef struct lora_channelplan { + uint8_t nb_channels; // number of channels + loramac_channel_t *channels; +} lorawan_channelplan_t; + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF12 - BW125 + * AU915 | SF10 - BW125 + * CN470 | SF12 - BW125 + * CN779 | SF12 - BW125 + * EU433 | SF12 - BW125 + * EU868 | SF12 - BW125 + * IN865 | SF12 - BW125 + * KR920 | SF12 - BW125 + * US915 | SF10 - BW125 + * US915_HYBRID | SF10 - BW125 + */ +#define DR_0 0 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF11 - BW125 + * AU915 | SF9 - BW125 + * CN470 | SF11 - BW125 + * CN779 | SF11 - BW125 + * EU433 | SF11 - BW125 + * EU868 | SF11 - BW125 + * IN865 | SF11 - BW125 + * KR920 | SF11 - BW125 + * US915 | SF9 - BW125 + * US915_HYBRID | SF9 - BW125 + */ +#define DR_1 1 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF10 - BW125 + * AU915 | SF8 - BW125 + * CN470 | SF10 - BW125 + * CN779 | SF10 - BW125 + * EU433 | SF10 - BW125 + * EU868 | SF10 - BW125 + * IN865 | SF10 - BW125 + * KR920 | SF10 - BW125 + * US915 | SF8 - BW125 + * US915_HYBRID | SF8 - BW125 + */ +#define DR_2 2 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF9 - BW125 + * AU915 | SF7 - BW125 + * CN470 | SF9 - BW125 + * CN779 | SF9 - BW125 + * EU433 | SF9 - BW125 + * EU868 | SF9 - BW125 + * IN865 | SF9 - BW125 + * KR920 | SF9 - BW125 + * US915 | SF7 - BW125 + * US915_HYBRID | SF7 - BW125 + */ +#define DR_3 3 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF8 - BW125 + * AU915 | SF8 - BW500 + * CN470 | SF8 - BW125 + * CN779 | SF8 - BW125 + * EU433 | SF8 - BW125 + * EU868 | SF8 - BW125 + * IN865 | SF8 - BW125 + * KR920 | SF8 - BW125 + * US915 | SF8 - BW500 + * US915_HYBRID | SF8 - BW500 + */ +#define DR_4 4 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF7 - BW125 + * AU915 | RFU + * CN470 | SF7 - BW125 + * CN779 | SF7 - BW125 + * EU433 | SF7 - BW125 + * EU868 | SF7 - BW125 + * IN865 | SF7 - BW125 + * KR920 | SF7 - BW125 + * US915 | RFU + * US915_HYBRID | RFU + */ +#define DR_5 5 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | SF7 - BW250 + * AU915 | RFU + * CN470 | SF12 - BW125 + * CN779 | SF7 - BW250 + * EU433 | SF7 - BW250 + * EU868 | SF7 - BW250 + * IN865 | SF7 - BW250 + * KR920 | RFU + * US915 | RFU + * US915_HYBRID | RFU + */ +#define DR_6 6 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | FSK + * AU915 | RFU + * CN470 | SF12 - BW125 + * CN779 | FSK + * EU433 | FSK + * EU868 | FSK + * IN865 | FSK + * KR920 | RFU + * US915 | RFU + * US915_HYBRID | RFU + */ +#define DR_7 7 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF12 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF12 - BW500 + * US915_HYBRID | SF12 - BW500 + */ +#define DR_8 8 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF11 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF11 - BW500 + * US915_HYBRID | SF11 - BW500 + */ +#define DR_9 9 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF10 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF10 - BW500 + * US915_HYBRID | SF10 - BW500 + */ +#define DR_10 10 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF9 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF9 - BW500 + * US915_HYBRID | SF9 - BW500 + */ +#define DR_11 11 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF8 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF8 - BW500 + * US915_HYBRID | SF8 - BW500 + */ +#define DR_12 12 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | SF7 - BW500 + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | SF7 - BW500 + * US915_HYBRID | SF7 - BW500 + */ +#define DR_13 13 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | RFU + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | RFU + * US915_HYBRID | RFU + */ +#define DR_14 14 + +/*! + * Region | SF + * ------------ | :-----: + * AS923 | RFU + * AU915 | RFU + * CN470 | RFU + * CN779 | RFU + * EU433 | RFU + * EU868 | RFU + * IN865 | RFU + * KR920 | RFU + * US915 | RFU + * US915_HYBRID | RFU + */ +#define DR_15 15 + +/** + * Enumeration for LoRaWAN connection type. + */ +typedef enum lorawan_connect_type { + LORAWAN_CONNECTION_OTAA = 0, /**< Over The Air Activation */ + LORAWAN_CONNECTION_ABP /**< Activation By Personalization */ +} lorawan_connect_type_t; + + +/** + * Meta-data collection for a transmission + */ +typedef struct { + /** + * The transmission time on air of the frame. + */ + uint32_t tx_toa; + /** + * The uplink channel used for transmission. + */ + uint32_t channel; + /** + * The transmission power. + */ + int8_t tx_power; + /** + * The uplink datarate. + */ + uint8_t data_rate; + /** + * Provides the number of retransmissions. + */ + uint8_t nb_retries; + /** + * A boolean to mark if the meta data is stale + */ + bool stale; +} lorawan_tx_metadata; + +/** + * Meta-data collection for the received packet + */ +typedef struct { + /** + * The RSSI for the received packet. + */ + int16_t rssi; + /** + * Data rate of reception + */ + uint8_t rx_datarate; + /** + * The SNR for the received packet. + */ + int8_t snr; + /** + * A boolean to mark if the meta data is stale + */ + bool stale; + /** + * Frequency for the downlink channel + */ + uint32_t channel; + /** + * Time spent on air by the RX frame + */ + uint32_t rx_toa; +} lorawan_rx_metadata; + +#endif /* MBED_LORAWAN_TYPES_H_ */ diff --git a/connectivity/lorawan/mbed_lib.json b/connectivity/lorawan/mbed_lib.json new file mode 100644 index 0000000..30e130b --- /dev/null +++ b/connectivity/lorawan/mbed_lib.json @@ -0,0 +1,97 @@ +{ + "name": "lora", + "config": { + "phy": { + "help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915", + "value": "EU868" + }, + "over-the-air-activation": { + "help": "When set to 1 the application uses the Over-the-Air activation procedure, default: true", + "value": true + }, + "nb-trials": { + "help": "Indicates how many times join can be tried, default: 12", + "value": 12 + }, + "device-eui": { + "help": "Mote device IEEE EUI", + "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + }, + "application-eui": { + "help": "Application IEEE EUI", + "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + }, + "application-key": { + "help": "AES encryption/decryption cipher application key", + "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + }, + "device-address": { + "help": "Device address on the network", + "value": "0x00000000" + }, + "nwkskey": { + "help": "AES encryption/decryption cipher network session key", + "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + }, + "appskey": { + "help": "AES encryption/decryption cipher application session key", + "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + }, + "app-port": { + "help": "LoRaWAN application port, default: 15", + "value": 15 + }, + "tx-max-size": { + "help": "User application data buffer maximum size, default: 64, MAX: 255", + "value": 64 + }, + "adr-on": { + "help": "LoRaWAN Adaptive Data Rate, default: 1", + "value": 1 + }, + "public-network": { + "help": "LoRaWAN will connect to a public network or private network, true = public network", + "value": true + }, + "duty-cycle-on": { + "help": "Enables/disables duty cycling. NOTE: Disable only for testing. Mandatory in many regions.", + "value": true + }, + "duty-cycle-on-join": { + "help": "Enables/disables duty cycling for JOIN requests (disabling requires duty-cycle-on to be disabled). NOTE: Disable only for testing!", + "value": true + }, + "lbt-on": { + "help": "Enables/disables LBT. NOTE: [This feature is not yet integrated].", + "value": false + }, + "automatic-uplink-message": { + "help": "Stack will automatically send an uplink message when lora server requires immediate response", + "value": true + }, + "max-sys-rx-error": { + "help": "Max. timing error fudge. The receiver will turn on in [-RxError : + RxError]", + "value": 5 + }, + "wakeup-time": { + "help": "Time in (ms) the platform takes to wakeup from sleep/deep sleep state. This number is platform dependent", + "value": 5 + }, + "downlink-preamble-length": { + "help": "Number of whole preamble symbols needed to have a firm lock on the signal.", + "value": 5 + }, + "uplink-preamble-length": { + "help": "Number of preamble symbols to transmit. Default: 8", + "value": 8 + }, + "fsb-mask": { + "help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details", + "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}" + }, + "fsb-mask-china": { + "help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details", + "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}" + } + } +} diff --git a/connectivity/lorawan/system/LoRaWANTimer.cpp b/connectivity/lorawan/system/LoRaWANTimer.cpp new file mode 100644 index 0000000..d17b96b --- /dev/null +++ b/connectivity/lorawan/system/LoRaWANTimer.cpp @@ -0,0 +1,66 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: Timer objects and scheduling management + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "LoRaWANTimer.h" + +using namespace std::chrono; + +LoRaWANTimeHandler::LoRaWANTimeHandler() + : _queue(NULL) +{ +} + +LoRaWANTimeHandler::~LoRaWANTimeHandler() +{ +} + +void LoRaWANTimeHandler::activate_timer_subsystem(events::EventQueue *queue) +{ + _queue = queue; +} + +lorawan_time_t LoRaWANTimeHandler::get_current_time(void) +{ + const uint32_t current_time = _queue->tick(); + return (lorawan_time_t)current_time; +} + +lorawan_time_t LoRaWANTimeHandler::get_elapsed_time(lorawan_time_t saved_time) +{ + return get_current_time() - saved_time; +} + +void LoRaWANTimeHandler::init(timer_event_t &obj, mbed::Callback callback) +{ + obj.callback = callback; + obj.timer_id = 0; +} + +void LoRaWANTimeHandler::start(timer_event_t &obj, const uint32_t timeout) +{ + obj.timer_id = _queue->call_in(milliseconds(timeout), obj.callback); + MBED_ASSERT(obj.timer_id != 0); +} + +void LoRaWANTimeHandler::stop(timer_event_t &obj) +{ + _queue->cancel(obj.timer_id); + obj.timer_id = 0; +} diff --git a/connectivity/lorawan/system/LoRaWANTimer.h b/connectivity/lorawan/system/LoRaWANTimer.h new file mode 100644 index 0000000..e66d268 --- /dev/null +++ b/connectivity/lorawan/system/LoRaWANTimer.h @@ -0,0 +1,83 @@ +/** + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: Timer objects and scheduling management + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian + + +Copyright (c) 2017, Arm Limited and affiliates. + +SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef MBED_LORAWAN_SYS_TIMER_H__ +#define MBED_LORAWAN_SYS_TIMER_H__ + +#include +#include "events/EventQueue.h" + +#include "lorawan_data_structures.h" + +class LoRaWANTimeHandler { +public: + LoRaWANTimeHandler(); + ~LoRaWANTimeHandler(); + + /** Activates the timer subsystem. + * + * Embeds EventQueue object to timer subsystem which is subsequently + * used to extract timer information. + * + * @param [in] queue Handle to EventQueue object + */ + void activate_timer_subsystem(events::EventQueue *queue); + + /** Read the current time. + * + * @return time The current time. + */ + lorawan_time_t get_current_time(void); + + /** Return the time elapsed since a fixed moment in time. + * + * @param [in] saved_time The fixed moment in time. + * @return time The elapsed time. + */ + lorawan_time_t get_elapsed_time(lorawan_time_t saved_time); + + /** Initializes the timer object. + * + * @remark The TimerSetValue function must be called before starting the timer. + * This function initializes the time-stamp and reloads the value at 0. + * + * @param [in] obj The structure containing the timer object parameters. + * @param [in] callback The function callback called at the end of the timeout. + */ + void init(timer_event_t &obj, mbed::Callback callback); + + /** Starts and adds the timer object to the list of timer events. + * + * @param [in] obj The structure containing the timer object parameters. + * @param [in] timeout The new timeout value. + */ + void start(timer_event_t &obj, const uint32_t timeout); + + /** Stops and removes the timer object from the list of timer events. + * + * @param [in] obj The structure containing the timer object parameters. + */ + void stop(timer_event_t &obj); + +private: + events::EventQueue *_queue; +}; + +#endif // MBED_LORAWAN_SYS_TIMER_H__ diff --git a/connectivity/lorawan/system/lorawan_data_structures.h b/connectivity/lorawan/system/lorawan_data_structures.h new file mode 100644 index 0000000..7ce8cb3 --- /dev/null +++ b/connectivity/lorawan/system/lorawan_data_structures.h @@ -0,0 +1,1313 @@ +/** + * @file lorawan_data_structures.h + * + * @brief Contains common data structures used by Mbed-OS + * LoRaWAN mplementation. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * Description: LoRa PHY layer + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) + * + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ +#define LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ + +#include +#include "lorawan_types.h" + +/*! + * \brief Timer time variable definition + */ +#ifndef lorawan_time_t +typedef uint32_t lorawan_time_t; +#endif + +/*! + * Sets the length of the LoRaMAC footer field. + * Mainly indicates the MIC field length. + */ +#define LORAMAC_MFR_LEN 4 + +/*! + * The FRMPayload overhead to be used when setting the `Radio.SetMaxPayloadLength` + * in the `RxWindowSetup` function. + * The maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD + */ +#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) + +/** + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 16 + +/** + * Maximum PHY layer payload size for reception. + */ +#define LORAMAC_PHY_MAXPAYLOAD 255 + +#define LORAWAN_DEFAULT_QOS 1 + +/** + * + * Default user application maximum data size for transmission + */ +// reject if user tries to set more than MTU +#if MBED_CONF_LORA_TX_MAX_SIZE > 255 +#warning "Cannot set TX Max size more than MTU=255" +#define MBED_CONF_LORA_TX_MAX_SIZE 255 +#endif + +/*! + * LoRaMAC band parameters definition. + */ +typedef struct { + /*! + * The duty cycle. + */ + uint16_t duty_cycle; + /*! + * The maximum TX power. + */ + int8_t max_tx_pwr; + /*! + * The timestamp of the last Join Request TX frame. + */ + lorawan_time_t last_join_tx_time; + /*! + * The timestamp of the last TX frame. + */ + lorawan_time_t last_tx_time; + /*! + * The device off time. + */ + lorawan_time_t off_time; + /*! + * Lower band boundry + */ + uint32_t lower_band_freq; + /*! + * Higher band boundry + */ + uint32_t higher_band_freq; +} band_t; + +/*! + * LoRaMAC receive window 2 channel parameters. + */ +typedef struct { + /*! + * The frequency in Hz. + */ + uint32_t frequency; + /*! + * The data rate. + * + * LoRaWAN Regional Parameters V1.0.2rB. + * + * The allowed ranges are region-specific. Please refer to \ref DR_0 to \ref DR_15 for details. + */ + uint8_t datarate; +} rx2_channel_params; + +/*! + * LoRaMAC receive window enumeration + */ +typedef enum { + /*! + * LoRaMAC receive window 1 + */ + RX_SLOT_WIN_1, + /*! + * LoRaMAC receive window 2 + */ + RX_SLOT_WIN_2, + /*! + * LoRaMAC receive window 2 for class c - continuous listening + */ + RX_SLOT_WIN_CLASS_C, + /*! + * LoRaMAC class b ping slot window + */ + RX_SLOT_WIN_PING_SLOT +} rx_slot_t; + +/*! + * The global MAC layer parameters. + */ +typedef struct { + /*! + * The TX power in channels. + */ + int8_t channel_tx_power; + /*! + * The data rate in channels. + */ + int8_t channel_data_rate; + /*! + * LoRaMac maximum time a reception window stays open. + */ + uint32_t max_rx_win_time; + /*! + * Receive delay 1. + */ + uint32_t recv_delay1; + /*! + * Receive delay 2. + */ + uint32_t recv_delay2; + /*! + * Join accept delay 1. + */ + uint32_t join_accept_delay1; + /*! + * Join accept delay 1. + */ + uint32_t join_accept_delay2; + /*! + * The number of uplink messages repetitions for QOS set by network server + * in LinkADRReq mac command (unconfirmed messages only). + */ + uint8_t nb_trans; + /*! + * The datarate offset between uplink and downlink on first window. + */ + uint8_t rx1_dr_offset; + /*! + * LoRaMAC 2nd reception window settings. + */ + rx2_channel_params rx2_channel; + /*! + * The uplink dwell time configuration. 0: No limit, 1: 400ms + */ + uint8_t uplink_dwell_time; + /*! + * The downlink dwell time configuration. 0: No limit, 1: 400ms + */ + uint8_t downlink_dwell_time; + /*! + * The maximum possible EIRP. + */ + float max_eirp; + /*! + * The antenna gain of the node. + */ + float antenna_gain; + + /*! + * Maximum duty cycle + * \remark Possibility to shutdown the device. + */ + uint8_t max_duty_cycle; + /*! + * Aggregated duty cycle management + */ + uint16_t aggregated_duty_cycle; + + /*! + * LoRaMac ADR control status + */ + bool adr_on; +} lora_mac_system_params_t; + +/*! + * LoRaMAC multicast channel parameter. + */ +typedef struct multicast_params_s { + /*! + * Address. + */ + uint32_t address; + /*! + * Network session key. + */ + uint8_t nwk_skey[16]; + /*! + * Application session key. + */ + uint8_t app_skey[16]; + /*! + * Downlink counter. + */ + uint32_t dl_frame_counter; + /*! + * A reference pointer to the next multicast channel parameters in the list. + */ + struct multicast_params_s *next; +} multicast_params_t; + +/*! + * LoRaMAC frame types. + * + * LoRaWAN Specification V1.0.2, chapter 4.2.1, table 1. + */ +typedef enum { + /*! + * LoRaMAC join request frame. + */ + FRAME_TYPE_JOIN_REQ = 0x00, + /*! + * LoRaMAC join accept frame. + */ + FRAME_TYPE_JOIN_ACCEPT = 0x01, + /*! + * LoRaMAC unconfirmed uplink frame. + */ + FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02, + /*! + * LoRaMAC unconfirmed downlink frame. + */ + FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03, + /*! + * LoRaMAC confirmed uplink frame. + */ + FRAME_TYPE_DATA_CONFIRMED_UP = 0x04, + /*! + * LoRaMAC confirmed downlink frame. + */ + FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05, + /*! + * LoRaMAC RFU frame. + */ + FRAME_TYPE_RFU = 0x06, + /*! + * LoRaMAC proprietary frame. + */ + FRAME_TYPE_PROPRIETARY = 0x07, +} mac_frame_type_t; + +/*! + * LoRaMAC mote MAC commands. + * + * LoRaWAN Specification V1.0.2, chapter 5, table 4. + */ +typedef enum { + /*! + * LinkCheckReq + */ + MOTE_MAC_LINK_CHECK_REQ = 0x02, + /*! + * LinkADRAns + */ + MOTE_MAC_LINK_ADR_ANS = 0x03, + /*! + * DutyCycleAns + */ + MOTE_MAC_DUTY_CYCLE_ANS = 0x04, + /*! + * RXParamSetupAns + */ + MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05, + /*! + * DevStatusAns + */ + MOTE_MAC_DEV_STATUS_ANS = 0x06, + /*! + * NewChannelAns + */ + MOTE_MAC_NEW_CHANNEL_ANS = 0x07, + /*! + * RXTimingSetupAns + */ + MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08, + /*! + * TXParamSetupAns + */ + MOTE_MAC_TX_PARAM_SETUP_ANS = 0x09, + /*! + * DlChannelAns + */ + MOTE_MAC_DL_CHANNEL_ANS = 0x0A +} mote_mac_cmds_t; + +/*! + * LoRaMAC server MAC commands. + * + * LoRaWAN Specification V1.0.2 chapter 5, table 4. + */ +typedef enum { + /*! + * LinkCheckAns + */ + SRV_MAC_LINK_CHECK_ANS = 0x02, + /*! + * LinkADRReq + */ + SRV_MAC_LINK_ADR_REQ = 0x03, + /*! + * DutyCycleReq + */ + SRV_MAC_DUTY_CYCLE_REQ = 0x04, + /*! + * RXParamSetupReq + */ + SRV_MAC_RX_PARAM_SETUP_REQ = 0x05, + /*! + * DevStatusReq + */ + SRV_MAC_DEV_STATUS_REQ = 0x06, + /*! + * NewChannelReq + */ + SRV_MAC_NEW_CHANNEL_REQ = 0x07, + /*! + * RXTimingSetupReq + */ + SRV_MAC_RX_TIMING_SETUP_REQ = 0x08, + /*! + * NewChannelReq + */ + SRV_MAC_TX_PARAM_SETUP_REQ = 0x09, + /*! + * DlChannelReq + */ + SRV_MAC_DL_CHANNEL_REQ = 0x0A, +} server_mac_cmds_t; + +/*! + * LoRaMAC battery level indicator. + */ +typedef enum { + /*! + * An external power source. + */ + BAT_LEVEL_EXT_SRC = 0x00, + /*! + * Battery level empty. + */ + BAT_LEVEL_EMPTY = 0x01, + /*! + * Battery level full. + */ + BAT_LEVEL_FULL = 0xFE, + /*! + * Battery level - no measurement available. + */ + BAT_LEVEL_NO_MEASURE = 0xFF, +} device_battery_level_t; + +/*! + * LoRaMAC header field definition (MHDR field). + * + * LoRaWAN Specification V1.0.2, chapter 4.2. + */ +typedef union { + /*! + * Byte-access to the bits. + */ + uint8_t value; + /*! + * The structure containing single access to header bits. + */ + struct hdr_bits_s { + /*! + * Major version. + */ + uint8_t major : 2; + /*! + * RFU + */ + uint8_t RFU : 3; + /*! + * Message type + */ + uint8_t mtype : 3; + } bits; +} loramac_mhdr_t; + +/*! + * LoRaMAC frame control field definition (FCtrl). + * + * LoRaWAN Specification V1.0.2, chapter 4.3.1. + */ +typedef union { + /*! + * Byte-access to the bits. + */ + uint8_t value; + /*! + * The structure containing single access to bits. + */ + struct ctrl_bits_s { + /*! + * Frame options length. + */ + uint8_t fopts_len : 4; + /*! + * Frame pending bit. + */ + uint8_t fpending : 1; + /*! + * Message acknowledge bit. + */ + uint8_t ack : 1; + /*! + * ADR acknowledgment request bit. + */ + uint8_t adr_ack_req : 1; + /*! + * ADR control in the frame header. + */ + uint8_t adr : 1; + } bits; +} loramac_frame_ctrl_t; + +/*! + * The enumeration containing the status of the operation of a MAC service. + */ +typedef enum { + /*! + * Service performed successfully. + */ + LORAMAC_EVENT_INFO_STATUS_OK = 0, + /*! + * An error occurred during the execution of the service. + */ + LORAMAC_EVENT_INFO_STATUS_ERROR, + /*! + * A TX timeout occurred. + */ + LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, + /*! + * An RX timeout occurred on receive window 1. + */ + LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, + /*! + * An RX timeout occurred on receive window 2. + */ + LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT, + /*! + * An RX error occurred on receive window 1. + */ + LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, + /*! + * An RX error occurred on receive window 2. + */ + LORAMAC_EVENT_INFO_STATUS_RX2_ERROR, + /*! + * An error occurred in the join procedure. + */ + LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, + /*! + * A frame with an invalid downlink counter was received. The + * downlink counter of the frame was equal to the local copy + * of the downlink counter of the node. + */ + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, + /*! + * The MAC could not retransmit a frame since the MAC decreased the datarate. The + * payload size is not applicable for the datarate. + */ + LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR, + /*! + * The node has lost MAX_FCNT_GAP or more frames. + */ + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOST, + /*! + * An address error occurred. + */ + LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, + /*! + * Message integrity check failure. + */ + LORAMAC_EVENT_INFO_STATUS_MIC_FAIL, + /*! + * Crypto methods failure + */ + LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL, +} loramac_event_info_status_t; + +/*! + * + * \brief LoRaMAC data services + * + * \details The following table list the primitives supported by a + * specific MAC data service: + * + * Name | Request | Indication | Response | Confirm + * --------------------- | :-----: | :--------: | :------: | :-----: + * \ref MCPS_UNCONFIRMED | YES | YES | NO | YES + * \ref MCPS_CONFIRMED | YES | YES | NO | YES + * \ref MCPS_MULTICAST | NO | YES | NO | NO + * \ref MCPS_PROPRIETARY | YES | YES | NO | YES + * + */ +typedef enum { + /*! + * Unconfirmed LoRaMAC frame. + */ + MCPS_UNCONFIRMED, + /*! + * Confirmed LoRaMAC frame. + */ + MCPS_CONFIRMED, + /*! + * Multicast LoRaMAC frame. + */ + MCPS_MULTICAST, + /*! + * Proprietary frame. + */ + MCPS_PROPRIETARY, +} mcps_type_t; + +/*! + * LoRaMAC MCPS-Confirm. + */ +typedef struct { + /*! + * Holds the previously performed MCPS-Request type. i.e., the type of + * the MCPS request for which this confirmation is being generated + */ + mcps_type_t req_type; + /*! + * The status of the operation. + */ + loramac_event_info_status_t status; + /*! + * The uplink datarate. + */ + uint8_t data_rate; + /*! + * The transmission power. + */ + int8_t tx_power; + /*! + * Set if an acknowledgement was received. + */ + bool ack_received; + /*! + * Provides the number of retransmissions. + */ + uint8_t nb_retries; + /*! + * The transmission time on air of the frame. + */ + lorawan_time_t tx_toa; + /*! + * The uplink counter value related to the frame. + */ + uint32_t ul_frame_counter; + /*! + * The uplink channel related to the frame. + */ + uint32_t channel; +} loramac_mcps_confirm_t; + +/*! + * LoRaMAC MCPS-Indication primitive. + */ +typedef struct { + /*! + * True if an MCPS indication was pending + */ + bool pending; + /*! + * MCPS-Indication type. + */ + mcps_type_t type; + /*! + * The status of the operation. + */ + loramac_event_info_status_t status; + /*! + * Multicast. + */ + uint8_t multicast; + /*! + * The application port. + */ + uint8_t port; + /*! + * The downlink datarate. + */ + uint8_t rx_datarate; + /*! + * Frame pending status. + */ + uint8_t fpending_status; + /*! + * A pointer to the received data stream. + */ + const uint8_t *buffer; + /*! + * The size of the received data stream. + */ + uint16_t buffer_size; + /*! + * Indicates, if data is available. + */ + bool is_data_recvd; + /*! + * The RSSI of the received packet. + */ + int16_t rssi; + /*! + * The SNR of the received packet. + */ + int8_t snr; + /*! + * The receive window. + * + * [0: Rx window 1, 1: Rx window 2] + */ + rx_slot_t rx_slot; + /*! + * Set if an acknowledgement was received. + */ + bool is_ack_recvd; + /*! + * The downlink counter value for the received frame. + */ + uint32_t dl_frame_counter; + /*! + * The downlink channel + */ + uint32_t channel; + /*! + * The time on air of the received frame. + */ + lorawan_time_t rx_toa; +} loramac_mcps_indication_t; + +/*! + * \brief LoRaMAC management services. + * + * \details The following table list the primitives supported by a + * specific MAC management service: + * + * Name | Request | Indication | Response | Confirm + * ---------------------------- | :-----: | :--------: | :------: | :-----: + * \ref MLME_JOIN | YES | NO | NO | YES + * \ref MLME_LINK_CHECK | YES | NO | NO | YES + * \ref MLME_TXCW | YES | NO | NO | YES + * \ref MLME_SCHEDULE_UPLINK | NO | YES | NO | NO + * + */ +typedef enum { + /*! + * Initiates the Over-the-Air activation. + * + * LoRaWAN Specification V1.0.2, chapter 6.2. + */ + MLME_JOIN, + /*! + * LinkCheckReq - Connectivity validation. + * + * LoRaWAN Specification V1.0.2, chapter 5, table 4. + */ + MLME_LINK_CHECK, + /*! + * Sets TX continuous wave mode. + * + * LoRaWAN end-device certification. + */ + MLME_TXCW, + /*! + * Sets TX continuous wave mode (new LoRa-Alliance CC definition). + * + * LoRaWAN end-device certification. + */ + MLME_TXCW_1, + /*! + * Indicates that the application shall perform an uplink as + * soon as possible. + */ + MLME_SCHEDULE_UPLINK +} mlme_type_t; + +/*! + * LoRaMAC MLME-Request for the join service. + */ +typedef struct { + /*! + * A globally unique end-device identifier. + * + * LoRaWAN Specification V1.0.2, chapter 6.2.1. + */ + uint8_t *dev_eui; + /*! + * An application identifier. + * + * LoRaWAN Specification V1.0.2, chapter 6.1.2 + */ + uint8_t *app_eui; + /*! + * AES-128 application key. + * + * LoRaWAN Specification V1.0.2, chapter 6.2.2. + */ + uint8_t *app_key; + /*! + * The number of trials for the join request. + */ + uint8_t nb_trials; +} mlme_join_req_t; + +/*! + * LoRaMAC MLME-Request for TX continuous wave mode. + */ +typedef struct { + /*! + * The time while the radio is kept in continuous wave mode, in seconds. + */ + uint16_t timeout; + /*! + * The RF frequency to set (only used with the new way). + */ + uint32_t frequency; + /*! + * The RF output power to set (only used with the new way). + */ + uint8_t power; +} mlme_cw_tx_mode_t; + + +/*! + * LoRaMAC MLME-Confirm primitive. + */ +typedef struct { + /*! + * Indicates if a request is pending or not + */ + bool pending; + /*! + * The previously performed MLME-Request. i.e., the request type + * for which the confirmation is being generated + */ + mlme_type_t req_type; + /*! + * The status of the operation. + */ + loramac_event_info_status_t status; + /*! + * The transmission time on air of the frame. + */ + lorawan_time_t tx_toa; + /*! + * The demodulation margin. Contains the link margin [dB] of the last LinkCheckReq + * successfully received. + */ + uint8_t demod_margin; + /*! + * The number of gateways which received the last LinkCheckReq. + */ + uint8_t nb_gateways; + /*! + * The number of retransmissions. + */ + uint8_t nb_retries; +} loramac_mlme_confirm_t; + +/*! + * LoRaMAC MLME-Indication primitive + */ +typedef struct { + /*! + * MLME-Indication type + */ + mlme_type_t indication_type; + bool pending; +} loramac_mlme_indication_t; + +/** + * End-device states. + */ +typedef enum device_states { + DEVICE_STATE_NOT_INITIALIZED, + DEVICE_STATE_JOINING, + DEVICE_STATE_IDLE, + DEVICE_STATE_CONNECTING, + DEVICE_STATE_AWAITING_JOIN_ACCEPT, + DEVICE_STATE_RECEIVING, + DEVICE_STATE_CONNECTED, + DEVICE_STATE_SCHEDULING, + DEVICE_STATE_SENDING, + DEVICE_STATE_AWAITING_ACK, + DEVICE_STATE_STATUS_CHECK, + DEVICE_STATE_SHUTDOWN +} device_states_t; + +/** + * Stack level TX message structure + */ +typedef struct { + + /** + * TX Ongoing flag + */ + bool tx_ongoing; + + /** + * Application Port Number + */ + uint8_t port; + + /** + * Message type + */ + mcps_type_t type; + + /*! + * Frame port field. Must be set if the payload is not empty. Use the + * application-specific frame port values: [1...223]. + * + * LoRaWAN Specification V1.0.2, chapter 4.3.2. + */ + uint8_t fport; + + /*! + * Uplink datarate, if ADR is off. + */ + int8_t data_rate; + /*! + * + * For CONFIRMED Messages: + * + * The number of trials to transmit the frame, if the LoRaMAC layer did not + * receive an acknowledgment. The MAC performs a datarate adaptation + * according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in + * the following table: + * + * Transmission nb | Data Rate + * ----------------|----------- + * 1 (first) | DR + * 2 | DR + * 3 | max(DR-1,0) + * 4 | max(DR-1,0) + * 5 | max(DR-2,0) + * 6 | max(DR-2,0) + * 7 | max(DR-3,0) + * 8 | max(DR-3,0) + * + * 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. + * + * 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; + + /** Payload data + * + * Base pointer to the buffer + */ + uint8_t f_buffer[MBED_CONF_LORA_TX_MAX_SIZE]; + + /** Payload size. + * + * The size of the frame payload. + */ + uint16_t f_buffer_size; + + /** + * Pending data size + */ + uint16_t pending_size; + +} loramac_tx_message_t; + +/** lora_mac_rx_message_type_t + * + * An enum representing a structure for RX messages. + */ +typedef enum { + LORAMAC_RX_MLME_CONFIRM = 0, /**< lora_mac_mlme_confirm_t */ + LORAMAC_RX_MCPS_CONFIRM, /**< lora_mac_mcps_confirm_t */ + LORAMAC_RX_MCPS_INDICATION /**< lora_mac_mcps_indication_t */ +} rx_msg_type; + +/** lora_mac_rx_message_by_type_t union + * + * A union representing a structure for RX messages. + */ +typedef union { + loramac_mlme_confirm_t mlme_confirm; + loramac_mcps_confirm_t mcps_confirm; + loramac_mcps_indication_t mcps_indication; +} rx_message_u; + +/** loramac_rx_message_t + * + * A structure representing a structure for an RX message. + */ +typedef struct { + bool receive_ready; + rx_msg_type type; + rx_message_u msg; + uint16_t pending_size; + uint16_t prev_read_size; +} loramac_rx_message_t; + +/** LoRaWAN session + * + * A structure for keeping session details. + */ +typedef struct lorawan_session { + /** + * True if the session is active + */ + bool active; + + /*! + * Select the connection type, either LORAWAN_CONNECTION_OTAA + * or LORAWAN_CONNECTION_ABP. + */ + uint8_t connect_type; + + /** + * LoRaWAN uplink counter + */ + uint32_t uplink_counter; + /** + * LoRaWAN downlink counter + */ + uint32_t downlink_counter; +} lorawan_session_t; + +/*! + * The parameter structure for the function for regional rx configuration. + */ +typedef struct { + /*! + * Type of modulation used (LoRa or FSK) + */ + uint8_t modem_type; + /*! + * The RX channel. + */ + uint8_t channel; + /*! + * The RX datarate index. + */ + uint8_t datarate; + /*! + * The RX bandwidth. + */ + uint8_t bandwidth; + /*! + * The RX datarate offset. + */ + int8_t dr_offset; + /*! + * The RX frequency. + */ + uint32_t frequency; + /*! + * The RX window timeout - Symbols + */ + uint32_t window_timeout; + /*! + * The RX window timeout - Milliseconds + */ + uint32_t window_timeout_ms; + /*! + * The RX window offset + */ + int32_t window_offset; + /*! + * The downlink dwell time. + */ + uint8_t dl_dwell_time; + /*! + * Set to true, if a repeater is supported. + */ + bool is_repeater_supported; + /*! + * Set to true, if RX should be continuous. + */ + bool is_rx_continuous; + /*! + * Sets the RX window. + */ + rx_slot_t rx_slot; +} rx_config_params_t; + +/*! + * \brief Timer object description + */ +typedef struct { + mbed::Callback callback; + int timer_id; +} timer_event_t; + +/*! + * A composite structure containing device identifiers and security keys + */ +typedef struct { + /*! + * Device IEEE EUI + */ + uint8_t *dev_eui; + + /*! + * Application IEEE EUI + */ + uint8_t *app_eui; + + /*! + * AES encryption/decryption cipher application key + */ + uint8_t *app_key; + + /*! + * AES encryption/decryption cipher network session key + * NOTE! LoRaMac determines the length of the key based on sizeof this variable + */ + uint8_t nwk_skey[16]; + + /*! + * AES encryption/decryption cipher application session key + * NOTE! LoRaMac determines the length of the key based on sizeof this variable + */ + uint8_t app_skey[16]; + +} loramac_keys; + +/*! + * A composite structure containing all the timers used in the LoRaWAN operation + */ +typedef struct { + /*! + * Aggregated duty cycle management + */ + lorawan_time_t aggregated_last_tx_time; + lorawan_time_t aggregated_timeoff; + + /*! + * Stores the time at LoRaMac initialization. + * + * \remark Used for the BACKOFF_DC computation. + */ + lorawan_time_t mac_init_time; + + /*! + * Last transmission time on air + */ + lorawan_time_t tx_toa; + + /*! + * LoRaMac duty cycle backoff timer + */ + timer_event_t backoff_timer; + + /*! + * LoRaMac reception windows timers + */ + timer_event_t rx_window1_timer; + timer_event_t rx_window2_timer; + + /*! + * Acknowledge timeout timer. Used for packet retransmissions. + */ + timer_event_t ack_timeout_timer; + +} lorawan_timers; + +/*! + * Global MAC layer configuration parameters + */ +typedef struct { + + /*! + * Holds the type of current Receive window slot + */ + rx_slot_t rx_slot; + + /*! + * Indicates if the node is connected to a private or public network + */ + bool is_nwk_public; + + /*! + * Indicates if the node supports repeaters + */ + bool is_repeater_supported; + + /*! + * Used for test purposes. Disables the opening of the reception windows. + */ + bool is_rx_window_enabled; + + /*! + * Indicates if the MAC layer has already joined a network. + */ + bool is_nwk_joined; + + /*! + * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates + * if the nodes needs to manage the server acknowledgement. + */ + bool is_node_ack_requested; + + /*! + * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates + * if the ACK bit must be set for the next transmission + */ + bool is_srv_ack_requested; + + /*! + * Enables/Disables duty cycle management (Test only) + */ + bool is_dutycycle_on; + + /*! + * Set to true, if the last uplink was a join request + */ + bool is_last_tx_join_request; + + /*! + * Indicates if the AckTimeout timer has expired or not + */ + bool is_ack_retry_timeout_expired; + + /*! + * Current channel index + */ + uint8_t channel; + + /*! + * Current channel index + */ + uint8_t last_channel_idx; + + /*! + * Uplink messages repetitions counter + */ + uint8_t ul_nb_rep_counter; + + /*! + * TX buffer used for encrypted outgoing frames + */ + uint8_t tx_buffer[LORAMAC_PHY_MAXPAYLOAD]; + + /*! + * Length of TX buffer + */ + uint16_t tx_buffer_len; + + /*! + * Used for storing decrypted RX data. + */ + uint8_t rx_buffer[LORAMAC_PHY_MAXPAYLOAD]; + + /*! + * Length of the RX buffer + */ + uint8_t rx_buffer_len; + + /*! + * Number of trials to get a frame acknowledged + */ + uint8_t max_ack_timeout_retries; + + /*! + * Number of trials to get a frame acknowledged + */ + uint8_t ack_timeout_retry_counter; + + /*! + * Maximum number of trials for the Join Request + */ + uint8_t max_join_request_trials; + + /*! + * Number of trials for the Join Request + */ + uint8_t join_request_trial_counter; + + /*! + * Mac keys + */ + loramac_keys keys; + + /*! + * Device nonce is a random value extracted by issuing a sequence of RSSI + * measurements + */ + uint16_t dev_nonce; + + /*! + * Network ID ( 3 bytes ) + */ + uint32_t net_id; + + /*! + * Mote Address + */ + uint32_t dev_addr; + + /*! + * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. + * Only the 16 LSB bits are sent + */ + uint32_t ul_frame_counter; + + /*! + * LoRaMAC frame counter. Each time a packet is received the counter is incremented. + * Only the 16 LSB bits are received + */ + uint32_t dl_frame_counter; + + /*! + * Counts the number of missed ADR acknowledgements + */ + uint32_t adr_ack_counter; + + /*! + * LoRaMac reception windows delay + * \remark normal frame: RxWindowXDelay = ReceiveDelayX - Offset + * join frame : RxWindowXDelay = JoinAcceptDelayX - Offset + */ + uint32_t rx_window1_delay; + uint32_t rx_window2_delay; + + /*! + * Timer objects and stored values + */ + lorawan_timers timers; + + /*! + * LoRaMac parameters + */ + lora_mac_system_params_t sys_params; + + /*! + * Receive Window configurations for PHY layer + */ + rx_config_params_t rx_window1_config; + rx_config_params_t rx_window2_config; + + /*! + * Multicast channels linked list + */ + multicast_params_t *multicast_channels; + +} loramac_protocol_params; + +#endif /* LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ */ diff --git a/connectivity/lorawan/tests/TESTS/lorawan/loraradio/README.md b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/README.md new file mode 100644 index 0000000..562a24e --- /dev/null +++ b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/README.md @@ -0,0 +1,17 @@ +# Description + +This document describes how to run LoRaRadio API tests. + +## Configuring target HW + +Before starting to test, the target HW must be configured for the test. This can be done by either modifying the application configuration `json` file (if using currently supported Semtech SX1272 or SX1276 radios) or implementing driver construction into test source. + +The default mbed_app.json file provides configuration for some already supported HWs. + +## Running tests + +You can use the following command to run tests: + +`mbed test -n mbed-os-tests-lorawan-loraradio -m TARGET -t GCC_ARM --app-config mbed-os/TESTS/lorawan/loraradio/template_mbed_app.txt` + +Replace TARGET with the target device. diff --git a/connectivity/lorawan/tests/TESTS/lorawan/loraradio/main.cpp b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/main.cpp new file mode 100644 index 0000000..fa9706e --- /dev/null +++ b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/main.cpp @@ -0,0 +1,291 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] LORADIO test cases require a RTOS to run. +#else + +#include "utest.h" +#include "unity.h" +#include "greentea-client/test_env.h" + +#include "Semaphore.h" + +#include "mbed_trace.h" +#define TRACE_GROUP "RTST" + +#include "LoRaRadio.h" + +#define SX1272 0xFF +#define SX1276 0xEE + +#if (MBED_CONF_APP_LORA_RADIO == SX1272) +#include "SX1272_LoRaRadio.h" +#elif (MBED_CONF_APP_LORA_RADIO == SX1276) +#include "SX1276_LoRaRadio.h" +#else +#error [NOT_SUPPORTED] Requires parameters from application config file. +#endif + +#if (MBED_CONF_APP_LORA_RADIO == SX1272) || (MBED_CONF_APP_LORA_RADIO == SX1276) + +using namespace utest::v1; +using namespace mbed; + +static LoRaRadio *radio = NULL; +rtos::Semaphore event_sem(0); + +enum event_t { + EV_NONE, + EV_TX_DONE, + EV_TX_TIMEOUT, + EV_RX_DONE, + EV_RX_TIMEOUT, + EV_RX_ERROR, +}; +static volatile event_t received_event; + + +static void tx_done() +{ + ThisThread::sleep_for(2); + TEST_ASSERT_EQUAL(EV_NONE, received_event); + received_event = EV_TX_DONE; + TEST_ASSERT_EQUAL(osOK, event_sem.release()); +} + +static void tx_timeout() +{ + ThisThread::sleep_for(2); + TEST_ASSERT_EQUAL(EV_NONE, received_event); + received_event = EV_TX_TIMEOUT; + TEST_ASSERT_EQUAL(osOK, event_sem.release()); +} + +static void rx_done(const uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) +{ + ThisThread::sleep_for(2); + TEST_ASSERT_EQUAL(EV_NONE, received_event); + received_event = EV_RX_DONE; + TEST_ASSERT_EQUAL(osOK, event_sem.release()); +} + +static void rx_timeout() +{ + ThisThread::sleep_for(2); + TEST_ASSERT_EQUAL(EV_NONE, received_event); + received_event = EV_RX_TIMEOUT; + TEST_ASSERT_EQUAL(osOK, event_sem.release()); +} + +static void rx_error() +{ + ThisThread::sleep_for(2); + TEST_ASSERT_EQUAL(EV_NONE, received_event); + received_event = EV_RX_ERROR; + TEST_ASSERT_EQUAL(osOK, event_sem.release()); +} + +static radio_events radio_callbacks = { + .tx_done = tx_done, + .tx_timeout = tx_timeout, + .rx_done = rx_done, + .rx_timeout = rx_timeout, + .rx_error = rx_error +}; + + +void test_random() +{ + const uint32_t rand1 = radio->random(); + const uint32_t rand2 = radio->random(); + TEST_ASSERT_NOT_EQUAL(rand1, rand2); +} + +void test_set_tx_config() +{ + uint8_t buffer[] = {0}; + + TEST_ASSERT_EQUAL(RF_IDLE, radio->get_status()); + + radio->set_tx_config(MODEM_LORA, 13, 0, + 0, 7, + 1, 8, + false, true, false, + 0, false, 100); + radio->send(buffer, sizeof(buffer)); + + TEST_ASSERT_EQUAL(RF_TX_RUNNING, radio->get_status()); + + TEST_ASSERT_TRUE(event_sem.try_acquire_for(1000)); + TEST_ASSERT_EQUAL(EV_TX_DONE, received_event); + received_event = EV_NONE; +} + +void test_set_rx_config() +{ + TEST_ASSERT_EQUAL(RF_IDLE, radio->get_status()); + + radio->set_rx_config(MODEM_LORA, 0, // modem, bandwidth, + 7, 1, // datarate, coderate, + 0, 8, // bandwidth_afc, preamble_len, + 24, false, // symb_timeout, fix_len, + 0, // payload_len, + false, false, 0, // crc_on, freq_hop_on, hop_period, + true, false); // iq_inverted, rx_continuous + radio->receive(100); + + TEST_ASSERT_EQUAL(RF_RX_RUNNING, radio->get_status()); + + TEST_ASSERT_TRUE(event_sem.try_acquire_for(1000)); + + // Nobody was sending to us so timeout is expected. + TEST_ASSERT_EQUAL(EV_RX_TIMEOUT, received_event); + received_event = EV_NONE; +} + +void test_time_on_air() +{ + radio->set_rx_config(MODEM_LORA, 0, + 7, 1, + 0, 8, + 24, false, + 0, + false, false, 0, + true, false); + TEST_ASSERT_EQUAL(52, radio->time_on_air(MODEM_LORA, 20)); + + radio->set_tx_config(MODEM_LORA, 13, 0, + 0, 7, + 1, 8, + false, true, false, + 0, false, 100); + TEST_ASSERT_EQUAL(72, radio->time_on_air(MODEM_LORA, 32)); + + // TODO: Add FSK tests +} + +void test_perform_carrier_sense() +{ + TEST_ASSERT_TRUE(radio->perform_carrier_sense(MODEM_FSK, 865000000, -20, 1)); + TEST_ASSERT_TRUE(radio->perform_carrier_sense(MODEM_LORA, 865000000, -20, 1)); +} + +void test_check_rf_frequency() +{ + // Test EU868 frequency + TEST_ASSERT_TRUE(radio->check_rf_frequency(865000000)); +} + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(20, "default_auto"); + + mbed_trace_init(); + + return verbose_test_setup_handler(number_of_cases); +} + +utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) +{ +#if (MBED_CONF_APP_LORA_RADIO == SX1272) + + radio = new SX1272_LoRaRadio(MBED_CONF_APP_LORA_SPI_MOSI, + MBED_CONF_APP_LORA_SPI_MISO, + MBED_CONF_APP_LORA_SPI_SCLK, + MBED_CONF_APP_LORA_CS, + MBED_CONF_APP_LORA_RESET, + MBED_CONF_APP_LORA_DIO0, + MBED_CONF_APP_LORA_DIO1, + MBED_CONF_APP_LORA_DIO2, + MBED_CONF_APP_LORA_DIO3, + MBED_CONF_APP_LORA_DIO4, + MBED_CONF_APP_LORA_DIO5, + MBED_CONF_APP_LORA_RF_SWITCH_CTL1, + MBED_CONF_APP_LORA_RF_SWITCH_CTL2, + MBED_CONF_APP_LORA_TXCTL, + MBED_CONF_APP_LORA_RXCTL, + MBED_CONF_APP_LORA_ANT_SWITCH, + MBED_CONF_APP_LORA_PWR_AMP_CTL, + MBED_CONF_APP_LORA_TCXO); + +#elif (MBED_CONF_APP_LORA_RADIO == SX1276) + + radio = new SX1276_LoRaRadio(MBED_CONF_APP_LORA_SPI_MOSI, + MBED_CONF_APP_LORA_SPI_MISO, + MBED_CONF_APP_LORA_SPI_SCLK, + MBED_CONF_APP_LORA_CS, + MBED_CONF_APP_LORA_RESET, + MBED_CONF_APP_LORA_DIO0, + MBED_CONF_APP_LORA_DIO1, + MBED_CONF_APP_LORA_DIO2, + MBED_CONF_APP_LORA_DIO3, + MBED_CONF_APP_LORA_DIO4, + MBED_CONF_APP_LORA_DIO5, + MBED_CONF_APP_LORA_RF_SWITCH_CTL1, + MBED_CONF_APP_LORA_RF_SWITCH_CTL2, + MBED_CONF_APP_LORA_TXCTL, + MBED_CONF_APP_LORA_RXCTL, + MBED_CONF_APP_LORA_ANT_SWITCH, + MBED_CONF_APP_LORA_PWR_AMP_CTL, + MBED_CONF_APP_LORA_TCXO); + +#else +#error [NOT_SUPPORTED] Unknown LoRa radio specified (SX1272,SX1276 are valid) +#endif + + TEST_ASSERT(radio); + radio->init_radio(&radio_callbacks); + radio->sleep(); + + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) +{ + radio->sleep(); + +#if (MBED_CONF_APP_LORA_RADIO == SX1272) + delete static_cast(radio); +#elif (MBED_CONF_APP_LORA_RADIO == SX1276) + delete static_cast(radio); +#else +#error [NOT_SUPPORTED] Unknown LoRa radio specified (SX1272,SX1276 are valid) +#endif + radio = NULL; + + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +const Case cases[] = { + Case("Test random", case_setup_handler, test_random, case_teardown_handler), + Case("Test set_tx_config", case_setup_handler, test_set_tx_config, case_teardown_handler), + Case("Test set_rx_config", case_setup_handler, test_set_rx_config, case_teardown_handler), + Case("Test time_on_air", case_setup_handler, test_time_on_air, case_teardown_handler), + Case("Test perform_carrier_sense", case_setup_handler, test_perform_carrier_sense, case_teardown_handler), + Case("Test check_rf_frequency", case_setup_handler, test_check_rf_frequency, case_teardown_handler), +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + +#endif // (MBED_CONF_APP_LORA_RADIO == SX1272) || (MBED_CONF_APP_LORA_RADIO == SX1276) +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/connectivity/lorawan/tests/TESTS/lorawan/loraradio/template_mbed_app.txt b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/template_mbed_app.txt new file mode 100644 index 0000000..a4d6fd5 --- /dev/null +++ b/connectivity/lorawan/tests/TESTS/lorawan/loraradio/template_mbed_app.txt @@ -0,0 +1,160 @@ +{ + "config": { + "lora-radio": { + "help": "Which radio to use (options: SX1272,SX1276)", + "value": "SX1276" + }, + + "lora-spi-mosi": { "value": "NC" }, + "lora-spi-miso": { "value": "NC" }, + "lora-spi-sclk": { "value": "NC" }, + "lora-cs": { "value": "NC" }, + "lora-reset": { "value": "NC" }, + "lora-dio0": { "value": "NC" }, + "lora-dio1": { "value": "NC" }, + "lora-dio2": { "value": "NC" }, + "lora-dio3": { "value": "NC" }, + "lora-dio4": { "value": "NC" }, + "lora-dio5": { "value": "NC" }, + "lora-rf-switch-ctl1": { "value": "NC" }, + "lora-rf-switch-ctl2": { "value": "NC" }, + "lora-txctl": { "value": "NC" }, + "lora-rxctl": { "value": "NC" }, + "lora-ant-switch": { "value": "NC" }, + "lora-pwr-amp-ctl": { "value": "NC" }, + "lora-tcxo": { "value": "NC" } + }, + "target_overrides": { + + "K64F": { + "lora-spi-mosi": "D11", + "lora-spi-miso": "D12", + "lora-spi-sclk": "D13", + "lora-cs": "D10", + "lora-reset": "A0", + "lora-dio0": "D2", + "lora-dio1": "D3", + "lora-dio2": "D4", + "lora-dio3": "D5", + "lora-dio4": "D8", + "lora-dio5": "D9", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "NC", + "lora-rxctl": "NC", + "lora-ant-switch": "A4", + "lora-pwr-amp-ctl": "NC", + "lora-tcxo": "NC" + }, + + "DISCO_L072CZ_LRWAN1": { + "lora-radio": "SX1276", + "lora-spi-mosi": "PA_7", + "lora-spi-miso": "PA_6", + "lora-spi-sclk": "PB_3", + "lora-cs": "PA_15", + "lora-reset": "PC_0", + "lora-dio0": "PB_4", + "lora-dio1": "PB_1", + "lora-dio2": "PB_0", + "lora-dio3": "PC_13", + "lora-dio4": "NC", + "lora-dio5": "NC", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "PC_2", + "lora-rxctl": "PA_1", + "lora-ant-switch": "NC", + "lora-pwr-amp-ctl": "PC_1", + "lora-tcxo": "PA_12" + }, + + "XDOT_L151CC": { + "lora-radio": "SX1272", + "lora-spi-mosi": "LORA_MOSI", + "lora-spi-miso": "LORA_MISO", + "lora-spi-sclk": "LORA_SCK", + "lora-cs": "LORA_NSS", + "lora-reset": "LORA_RESET", + "lora-dio0": "LORA_DIO0", + "lora-dio1": "LORA_DIO1", + "lora-dio2": "LORA_DIO2", + "lora-dio3": "LORA_DIO3", + "lora-dio4": "LORA_DIO4", + "lora-dio5": "NC", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "NC", + "lora-rxctl": "NC", + "lora-ant-switch": "NC", + "lora-pwr-amp-ctl": "NC", + "lora-tcxo": "NC" + }, + + "LTEK_FF1705": { + "lora-radio": "SX1272", + "lora-spi-mosi": "LORA_MOSI", + "lora-spi-miso": "LORA_MISO", + "lora-spi-sclk": "LORA_SCK", + "lora-cs": "LORA_NSS", + "lora-reset": "LORA_RESET", + "lora-dio0": "LORA_DIO0", + "lora-dio1": "LORA_DIO1", + "lora-dio2": "LORA_DIO2", + "lora-dio3": "LORA_DIO3", + "lora-dio4": "LORA_DIO4", + "lora-dio5": "NC", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "NC", + "lora-rxctl": "NC", + "lora-ant-switch": "NC", + "lora-pwr-amp-ctl": "NC", + "lora-tcxo": "NC" + }, + + "MTS_MDOT_F411RE": { + "lora-radio": "SX1272", + "lora-spi-mosi": "LORA_MOSI", + "lora-spi-miso": "LORA_MISO", + "lora-spi-sclk": "LORA_SCK", + "lora-cs": "LORA_NSS", + "lora-reset": "LORA_RESET", + "lora-dio0": "LORA_DIO0", + "lora-dio1": "LORA_DIO1", + "lora-dio2": "LORA_DIO2", + "lora-dio3": "LORA_DIO3", + "lora-dio4": "LORA_DIO4", + "lora-dio5": "LORA_DIO5", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "LORA_TXCTL", + "lora-rxctl": "LORA_RXCTL", + "lora-ant-switch": "NC", + "lora-pwr-amp-ctl": "NC", + "lora-tcxo": "NC" + }, + + "ADV_WISE_1510": { + "lora-radio": "SX1276", + "lora-spi-mosi": "SPI_RF_MOSI", + "lora-spi-miso": "SPI_RF_MISO", + "lora-spi-sclk": "SPI_RF_SCK", + "lora-cs": "SPI_RF_CS", + "lora-reset": "SPI_RF_RESET", + "lora-dio0": "DIO0", + "lora-dio1": "DIO1", + "lora-dio2": "DIO2", + "lora-dio3": "DIO3", + "lora-dio4": "DIO4", + "lora-dio5": "DIO5", + "lora-rf-switch-ctl1": "NC", + "lora-rf-switch-ctl2": "NC", + "lora-txctl": "NC", + "lora-rxctl": "NC", + "lora-ant-switch": "ANT_SWITCH", + "lora-pwr-amp-ctl": "NC", + "lora-tcxo": "NC" + } + } +} diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp new file mode 100644 index 0000000..8edee42 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/Test_LoRaMac.cpp @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaMac.h" +#include "LoRaPHY_stub.h" +#include "LoRaMacCrypto_stub.h" +#include "LoRaMacCommand_stub.h" +#include "LoRaWANTimer_stub.h" +#include "EventQueue_stub.h" + +using namespace events; + +class my_phy : public LoRaPHY { +public: + my_phy() + { + }; + + virtual ~my_phy() + { + }; +}; + +class Test_LoRaMac : public testing::Test { +protected: + LoRaMac *object; + + virtual void SetUp() + { + object = new LoRaMac(); + LoRaWANTimer_stub::time_value = 1; + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaMac, constructor) +{ + EXPECT_TRUE(object); +} + +void my_cb() +{ + +} + +TEST_F(Test_LoRaMac, initialize) +{ + my_phy phy; + object->bind_phy(phy); + + lorawan_connect_t conn; + memset(&conn, 0, sizeof(conn)); + uint8_t key[16]; + memset(key, 0, sizeof(key)); + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 2; + object->prepare_join(&conn, true); + + channel_params_t params[] = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; + LoRaPHY_stub::channel_params_ptr = params; + + LoRaWANTimer_stub::call_cb_immediately = true; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb)); +} + +TEST_F(Test_LoRaMac, disconnect) +{ + object->disconnect(); +} + +TEST_F(Test_LoRaMac, nwk_joined) +{ + EXPECT_EQ(false, object->nwk_joined()); +} + +TEST_F(Test_LoRaMac, add_channel_plan) +{ + lorawan_channelplan_t plan; + EXPECT_EQ(LORAWAN_STATUS_OK, object->add_channel_plan(plan)); + + object->set_tx_ongoing(true); + EXPECT_EQ(LORAWAN_STATUS_BUSY, object->add_channel_plan(plan)); +} + +TEST_F(Test_LoRaMac, remove_channel_plan) +{ + EXPECT_EQ(LORAWAN_STATUS_OK, object->remove_channel_plan()); + + object->set_tx_ongoing(true); + EXPECT_EQ(LORAWAN_STATUS_BUSY, object->remove_channel_plan()); +} + +TEST_F(Test_LoRaMac, get_channel_plan) +{ + lorawan_channelplan_t plan; + EXPECT_EQ(LORAWAN_STATUS_OK, object->get_channel_plan(plan)); +} + +TEST_F(Test_LoRaMac, remove_single_channel) +{ + EXPECT_EQ(LORAWAN_STATUS_OK, object->remove_single_channel(1)); + + object->set_tx_ongoing(true); + EXPECT_EQ(LORAWAN_STATUS_BUSY, object->remove_single_channel(1)); +} + +TEST_F(Test_LoRaMac, multicast_channel_link) +{ + multicast_params_t p; + memset(&p, 0, sizeof(p)); + + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->multicast_channel_link(NULL)); + + object->set_tx_ongoing(true); + EXPECT_EQ(LORAWAN_STATUS_BUSY, object->multicast_channel_link(&p)); + + object->set_tx_ongoing(false); + EXPECT_EQ(LORAWAN_STATUS_OK, object->multicast_channel_link(&p)); +} + +TEST_F(Test_LoRaMac, multicast_channel_unlink) +{ + multicast_params_t p; + memset(&p, 0, sizeof(p)); + + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->multicast_channel_unlink(NULL)); + + object->set_tx_ongoing(true); + EXPECT_EQ(LORAWAN_STATUS_BUSY, object->multicast_channel_unlink(&p)); + + object->set_tx_ongoing(false); + EXPECT_EQ(LORAWAN_STATUS_OK, object->multicast_channel_unlink(&p)); +} + +TEST_F(Test_LoRaMac, send) +{ + loramac_mhdr_t mac_hdr; + memset(&mac_hdr, 0, sizeof(mac_hdr)); + uint8_t buf[15]; + memset(buf, 0, sizeof(buf)); + mac_hdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; + object->send(&mac_hdr, 1, buf, 15); +} + +TEST_F(Test_LoRaMac, get_default_tx_datarate) +{ + object->get_default_tx_datarate(); +} + +TEST_F(Test_LoRaMac, enable_adaptive_datarate) +{ + object->enable_adaptive_datarate(true); +} + +TEST_F(Test_LoRaMac, set_channel_data_rate) +{ + object->set_channel_data_rate(8); +} + +TEST_F(Test_LoRaMac, tx_ongoing) +{ + object->tx_ongoing(); +} + +TEST_F(Test_LoRaMac, set_tx_ongoing) +{ + object->set_tx_ongoing(true); +} + +TEST_F(Test_LoRaMac, reset_ongoing_tx) +{ + object->reset_ongoing_tx(true); +} + +TEST_F(Test_LoRaMac, prepare_ongoing_tx) +{ + uint8_t buf[16]; + memset(buf, 0, sizeof(buf)); + object->prepare_ongoing_tx(1, buf, 16, 1, 0); +} + +TEST_F(Test_LoRaMac, send_ongoing_tx) +{ + object->send_ongoing_tx(); +} + +TEST_F(Test_LoRaMac, get_device_class) +{ + object->get_device_class(); +} + +void exp_cb() +{ + +} + +TEST_F(Test_LoRaMac, set_device_class) +{ + object->set_device_class(CLASS_B, exp_cb); + + my_phy phy; + object->bind_phy(phy); + object->set_device_class(CLASS_C, exp_cb); +} + +TEST_F(Test_LoRaMac, setup_link_check_request) +{ + object->setup_link_check_request(); +} + +TEST_F(Test_LoRaMac, prepare_join) +{ + lorawan_connect_t conn; + memset(&conn, 0, sizeof(conn)); + object->prepare_join(&conn, false); + + my_phy phy; + object->bind_phy(phy); + EXPECT_EQ(LORAWAN_STATUS_OK, object->join(false)); + + uint8_t key[16]; + conn.connection_u.otaa.app_key = NULL; + conn.connection_u.otaa.app_eui = NULL; + conn.connection_u.otaa.dev_eui = NULL; + conn.connection_u.otaa.nb_trials = 0; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); + + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = NULL; + conn.connection_u.otaa.dev_eui = NULL; + conn.connection_u.otaa.nb_trials = 0; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); + + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = NULL; + conn.connection_u.otaa.nb_trials = 0; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); + + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 0; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, true)); + + LoRaPHY_stub::bool_table[0] = false; + LoRaPHY_stub::bool_counter = 0; + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 2; + EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(&conn, true)); + + conn.connection_u.abp.dev_addr = 0; + conn.connection_u.abp.nwk_id = 0; + conn.connection_u.abp.nwk_skey = NULL; + conn.connection_u.abp.app_skey = NULL; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); + + conn.connection_u.abp.dev_addr = 1; + conn.connection_u.abp.nwk_id = 0; + conn.connection_u.abp.nwk_skey = NULL; + conn.connection_u.abp.app_skey = NULL; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); + + conn.connection_u.abp.dev_addr = 1; + conn.connection_u.abp.nwk_id = 2; + conn.connection_u.abp.nwk_skey = NULL; + conn.connection_u.abp.app_skey = NULL; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); + + conn.connection_u.abp.dev_addr = 1; + conn.connection_u.abp.nwk_id = 2; + conn.connection_u.abp.nwk_skey = key; + conn.connection_u.abp.app_skey = NULL; + EXPECT_EQ(LORAWAN_STATUS_PARAMETER_INVALID, object->prepare_join(&conn, false)); + + conn.connection_u.abp.dev_addr = 1; + conn.connection_u.abp.nwk_id = 2; + conn.connection_u.abp.nwk_skey = key; + conn.connection_u.abp.app_skey = key; + EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(&conn, false)); + + EXPECT_EQ(LORAWAN_STATUS_OK, object->prepare_join(NULL, false)); +} + +TEST_F(Test_LoRaMac, join) +{ + my_phy phy; + object->bind_phy(phy); + EXPECT_EQ(LORAWAN_STATUS_OK, object->join(false)); + + lorawan_connect_t conn; + memset(&conn, 0, sizeof(conn)); + uint8_t key[16]; + memset(key, 0, sizeof(key)); + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 2; + object->prepare_join(&conn, true); + EXPECT_EQ(LORAWAN_STATUS_CONNECT_IN_PROGRESS, object->join(true)); +} + +TEST_F(Test_LoRaMac, on_radio_tx_done) +{ + my_phy phy; + object->bind_phy(phy); + object->on_radio_tx_done(100); +} + +TEST_F(Test_LoRaMac, on_radio_rx_done) +{ + uint8_t buf[16]; + memset(buf, 0, sizeof(buf)); + object->on_radio_rx_done(buf, 16, 0, 0); +} + +TEST_F(Test_LoRaMac, on_radio_tx_timeout) +{ + object->on_radio_tx_timeout(); +} + +TEST_F(Test_LoRaMac, on_radio_rx_timeout) +{ + object->on_radio_rx_timeout(true); +} + +TEST_F(Test_LoRaMac, continue_joining_process) +{ + my_phy phy; + object->bind_phy(phy); + lorawan_connect_t conn; + memset(&conn, 0, sizeof(conn)); + uint8_t key[16]; + memset(key, 0, sizeof(key)); + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 2; + object->prepare_join(&conn, true); + object->continue_joining_process(); +} + +TEST_F(Test_LoRaMac, continue_sending_process) +{ + my_phy phy; + object->bind_phy(phy); + object->continue_sending_process(); +} + +TEST_F(Test_LoRaMac, get_mcps_confirmation) +{ + object->get_mcps_confirmation(); +} + +TEST_F(Test_LoRaMac, get_mcps_indication) +{ + object->get_mcps_indication(); +} + +TEST_F(Test_LoRaMac, get_mlme_confirmation) +{ + object->get_mlme_confirmation(); +} + +TEST_F(Test_LoRaMac, get_mlme_indication) +{ + object->get_mlme_indication(); +} + +TEST_F(Test_LoRaMac, post_process_mcps_req) +{ + uint8_t data[16]; + memset(data, 0, sizeof(data)); + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + + my_phy phy; + object->bind_phy(phy); + object->join(false); + + object->prepare_ongoing_tx(1, data, 15, 0x01, 2); + object->send_ongoing_tx(); + object->post_process_mcps_req(); + + LoRaPHY_stub::bool_counter = 0; + object->prepare_ongoing_tx(1, data, 15, 0x02, 2); + object->send_ongoing_tx(); + object->post_process_mcps_req(); + + //_mcps_confirmation.ack_received missing here + uint8_t payload[16] = {}; + LoRaPHY_stub::uint16_value = 5; + payload[0] = FRAME_TYPE_DATA_CONFIRMED_DOWN << 5; + payload[5] = 1 << 5; + + //address != _params.dev_addr + payload[2] = 2; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + payload[2] = 0; + //mic failure + payload[13] = 2; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + payload[13] = 0; + //crypto failure + LoRaMacCrypto_stub::int_table_idx_value = 0; + LoRaMacCrypto_stub::int_table[0] = 4; + LoRaMacCrypto_stub::int_table[1] = 4; +// LoRaPHY_stub::uint16_value = 0; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + //process_mac_commands failure + LoRaMacCommand_stub::status_value = LORAWAN_STATUS_BUSY; + LoRaMacCrypto_stub::int_table[0] = 0; + LoRaMacCrypto_stub::int_table[1] = 0; + payload[7] = 1; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + //FOpts_len != 0 + payload[5] = (1 << 5) + 1; + payload[7] = 0; + LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; + payload[0] = FRAME_TYPE_DATA_UNCONFIRMED_DOWN << 5; + + object->on_radio_rx_done(payload, 13, 0, 0); + + //_mac_commands.process_mac_commands fails + LoRaMacCommand_stub::status_value = LORAWAN_STATUS_DATARATE_INVALID; + object->on_radio_rx_done(payload, 13, 0, 0); + + object->post_process_mcps_req(); + + payload[9] = 1; + LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; + payload[0] = FRAME_TYPE_PROPRIETARY << 5; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + payload[9] = 0; + payload[5] = 1 << 5; + LoRaMacCommand_stub::status_value = LORAWAN_STATUS_OK; + object->on_radio_rx_done(payload, 16, 0, 0); + object->post_process_mcps_req(); + + LoRaPHY_stub::bool_counter = 0; + object->prepare_ongoing_tx(1, data, 15, 0x04, 2); + object->send_ongoing_tx(); + object->post_process_mcps_req(); + + LoRaPHY_stub::bool_counter = 0; + object->prepare_ongoing_tx(1, data, 15, 0x08, 2); + object->send_ongoing_tx(); + object->post_process_mcps_req(); +} + +TEST_F(Test_LoRaMac, handle_join_accept_frame) +{ + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + + my_phy phy; + object->bind_phy(phy); + + uint8_t payload[16] = {}; + LoRaPHY_stub::uint16_value = 5; + payload[0] = FRAME_TYPE_JOIN_ACCEPT << 5; + payload[5] = 1 << 5; + + LoRaMacCrypto_stub::int_table_idx_value = 0; + LoRaMacCrypto_stub::int_table[0] = 4; + LoRaMacCrypto_stub::int_table[1] = 4; + LoRaMacCrypto_stub::int_table[2] = 4; + LoRaMacCrypto_stub::int_table[3] = 4; + object->on_radio_rx_done(payload, 16, 0, 0); + + LoRaMacCrypto_stub::int_table_idx_value = 0; + LoRaMacCrypto_stub::int_table[0] = 0; + object->on_radio_rx_done(payload, 16, 0, 0); + + LoRaMacCrypto_stub::int_table_idx_value = 0; + LoRaMacCrypto_stub::int_table[1] = 0; + object->on_radio_rx_done(payload, 16, 0, 0); + + //mic failure case + payload[13] = 17; + LoRaMacCrypto_stub::int_table_idx_value = 0; + object->on_radio_rx_done(payload, 16, 0, 0); + + payload[13] = 0; + LoRaMacCrypto_stub::int_table_idx_value = 0; + LoRaMacCrypto_stub::int_table[2] = 0; + object->on_radio_rx_done(payload, 16, 0, 0); +} + +TEST_F(Test_LoRaMac, post_process_mcps_ind) +{ + object->post_process_mcps_ind(); +} + +TEST_F(Test_LoRaMac, post_process_mlme_request) +{ + object->post_process_mlme_request(); +} + +TEST_F(Test_LoRaMac, post_process_mlme_ind) +{ + object->post_process_mlme_ind(); +} + +uint8_t batt_cb() +{ + +} + +TEST_F(Test_LoRaMac, set_batterylevel_callback) +{ + object->set_batterylevel_callback(batt_cb); +} + +TEST_F(Test_LoRaMac, get_backoff_timer_event_id) +{ + object->get_backoff_timer_event_id(); +} + +TEST_F(Test_LoRaMac, clear_tx_pipe) +{ + EXPECT_EQ(LORAWAN_STATUS_NO_OP, object->clear_tx_pipe()); //timer id == 0 + + my_phy phy; + object->bind_phy(phy); + + lorawan_connect_t conn; + memset(&conn, 0, sizeof(conn)); + uint8_t key[16]; + memset(key, 0, sizeof(key)); + conn.connection_u.otaa.app_key = key; + conn.connection_u.otaa.app_eui = key; + conn.connection_u.otaa.dev_eui = key; + conn.connection_u.otaa.nb_trials = 2; + object->prepare_join(&conn, true); + + channel_params_t params[] = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; + LoRaPHY_stub::channel_params_ptr = params; + LoRaWANTimer_stub::call_cb_immediately = true; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL, my_cb)); + EventQueue_stub::int_value = 0; + 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; + EXPECT_EQ(LORAWAN_STATUS_OK, object->clear_tx_pipe()); +} + +TEST_F(Test_LoRaMac, get_current_time) +{ + object->get_current_time(); +} + +TEST_F(Test_LoRaMac, get_current_slot) +{ + object->get_current_slot(); +} + +TEST_F(Test_LoRaMac, get_QOS_level) +{ + EXPECT_EQ(0, object->get_QOS_level()); +} + +TEST_F(Test_LoRaMac, get_prev_QOS_level) +{ + EXPECT_EQ(1, object->get_prev_QOS_level()); +} diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/unittest.cmake new file mode 100644 index 0000000..f68bee2 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramac/unittest.cmake @@ -0,0 +1,63 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaMac") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/mac/LoRaMac.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/mac +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loramac/Test_LoRaMac.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANStack_stub.cpp + stubs/mbed_assert_stub.cpp + stubs/LoRaMacCrypto_stub.cpp + stubs/LoRaMacChannelPlan_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/LoRaMacCommand_stub.cpp + stubs/EventQueue_stub.cpp + stubs/Mutex_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_ADR_ON=true + -DMBED_CONF_LORA_PUBLIC_NETWORK=true + -DMBED_CONF_LORA_NB_TRIALS=2 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_DUTY_CYCLE_ON=true + -DMBED_CONF_LORA_MAX_SYS_RX_ERROR=10 + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DEVICE_ADDRESS=0x00000000 +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_NWKSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_NWKSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_APPSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_APPSKEY=\"{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\"") + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp new file mode 100644 index 0000000..7150ec1 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaMacChannelPlan.h" +#include "LoRaPHY_stub.h" +#include "LoRaPHY.h" + +class my_LoRaPHY : public LoRaPHY { +public: + my_LoRaPHY() + { + }; + + virtual ~my_LoRaPHY() + { + }; +}; + + +class Test_LoRaMacChannelPlan : public testing::Test { +protected: + LoRaMacChannelPlan *object; + my_LoRaPHY phy; + + virtual void SetUp() + { + object = new LoRaMacChannelPlan(); + object->activate_channelplan_subsystem(&phy); + + LoRaPHY_stub::uint8_value = 0; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_OK; + LoRaPHY_stub::uint16_value = 0; + memcpy(LoRaPHY_stub::bool_table, "0", 20); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaMacChannelPlan, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaMacChannelPlan, set_plan) +{ + lorawan_channelplan_t plan; + memset(&plan, 0, sizeof(plan)); + memset(&LoRaPHY_stub::bool_table, 0, sizeof(LoRaPHY_stub::bool_table)); + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = false; + EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_SERVICE_UNKNOWN); + + plan.nb_channels = 1; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_PARAMETER_INVALID); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::uint8_value = 10; + LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_PARAMETER_INVALID; + loramac_channel_t chan; + memset(&chan, 0, sizeof(chan)); + plan.channels = &chan; + EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_PARAMETER_INVALID); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + plan.nb_channels = 2; + LoRaPHY_stub::lorawan_status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(object->set_plan(plan) == LORAWAN_STATUS_OK); +} + +TEST_F(Test_LoRaMacChannelPlan, get_plan) +{ + lorawan_channelplan_t plan; + channel_params_t params; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = false; + EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_SERVICE_UNKNOWN); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = false; + + LoRaPHY_stub::uint8_value = 1; + LoRaPHY_stub::uint16_value = 0xABCD; + EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_OK); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = true; + LoRaPHY_stub::bool_table[2] = false; + loramac_channel_t ch; + plan.channels = &ch; + EXPECT_TRUE(object->get_plan(plan, ¶ms) == LORAWAN_STATUS_OK); +} + +TEST_F(Test_LoRaMacChannelPlan, remove_plan) +{ + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = false; + EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_SERVICE_UNKNOWN); + + LoRaPHY_stub::uint8_value = 4; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = true; //first continue + LoRaPHY_stub::bool_table[2] = false; + LoRaPHY_stub::bool_table[3] = false;//second continue + LoRaPHY_stub::bool_table[4] = false; + LoRaPHY_stub::bool_table[5] = true; + LoRaPHY_stub::bool_table[6] = false;//false for remove_single_channel(i) + + EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_SERVICE_UNKNOWN); + + LoRaPHY_stub::uint8_value = 3; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = false; + LoRaPHY_stub::bool_table[2] = true; + LoRaPHY_stub::bool_table[3] = true; + LoRaPHY_stub::bool_table[4] = true; + LoRaPHY_stub::bool_table[5] = true; + LoRaPHY_stub::bool_table[7] = true; + LoRaPHY_stub::bool_table[8] = true; + LoRaPHY_stub::bool_table[9] = true; + LoRaPHY_stub::bool_table[10] = true; + + EXPECT_TRUE(object->remove_plan() == LORAWAN_STATUS_OK); + +} + +TEST_F(Test_LoRaMacChannelPlan, remove_single_channel) +{ + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = false; + EXPECT_TRUE(object->remove_single_channel(4) == LORAWAN_STATUS_SERVICE_UNKNOWN); + + LoRaPHY_stub::uint8_value = 2; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + + EXPECT_TRUE(object->remove_single_channel(4) == LORAWAN_STATUS_PARAMETER_INVALID); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = false; + EXPECT_TRUE(object->remove_single_channel(1) == LORAWAN_STATUS_PARAMETER_INVALID); + + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = true; + EXPECT_TRUE(object->remove_single_channel(1) == LORAWAN_STATUS_OK); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake new file mode 100644 index 0000000..4bc3c0a --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramacchannelplan/unittest.cmake @@ -0,0 +1,40 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaMacChannelPlan") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/mac +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loramacchannelplan/Test_LoRaMacChannelPlan.cpp + stubs/LoRaPHY_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 +) diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp new file mode 100644 index 0000000..b9430ea --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaMacCommand.h" + +#include "LoRaPHY_stub.h" + +class my_LoRaPHY : public LoRaPHY { +public: + my_LoRaPHY() + { + }; + + virtual ~my_LoRaPHY() + { + }; +}; + +uint8_t my_cb() +{ + return 1; +} + +class Test_LoRaMacCommand : public testing::Test { +protected: + LoRaMacCommand *object; + + virtual void SetUp() + { + object = new LoRaMacCommand(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaMacCommand, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaMacCommand, get_mac_cmd_length) +{ + object->add_link_check_req(); + EXPECT_TRUE(object->get_mac_cmd_length() == 1); + object->clear_command_buffer(); + EXPECT_TRUE(object->get_mac_cmd_length() == 0); +} + +TEST_F(Test_LoRaMacCommand, parse_mac_commands_to_repeat) +{ + loramac_mlme_confirm_t mlme; + lora_mac_system_params_t params; + my_LoRaPHY phy; + uint8_t buf[20]; + + object->parse_mac_commands_to_repeat(); + + buf[0] = 2; + buf[1] = 16; + buf[2] = 32; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 3, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 3; + LoRaPHY_stub::uint8_value = 7; + LoRaPHY_stub::linkAdrNbBytesParsed = 5; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 4; + buf[1] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 5; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 6; + object->set_batterylevel_callback(my_cb); + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 7; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 8; + buf[1] = 0; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 9; + buf[1] = 48; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 10; + buf[1] = 4; + buf[2] = 2; + buf[3] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + object->parse_mac_commands_to_repeat(); +} + +TEST_F(Test_LoRaMacCommand, clear_repeat_buffer) +{ + object->clear_repeat_buffer(); +} + +TEST_F(Test_LoRaMacCommand, copy_repeat_commands_to_buffer) +{ + loramac_mlme_confirm_t mlme; + lora_mac_system_params_t params; + my_LoRaPHY phy; + uint8_t buf[20]; + + object->clear_command_buffer(); + buf[0] = 5; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + object->parse_mac_commands_to_repeat(); + + object->clear_command_buffer(); + EXPECT_TRUE(object->get_mac_cmd_length() == 0); + + object->copy_repeat_commands_to_buffer(); + + EXPECT_TRUE(object->get_mac_cmd_length() != 0); +} + +TEST_F(Test_LoRaMacCommand, get_repeat_commands_length) +{ + EXPECT_TRUE(object->get_repeat_commands_length() == 0); +} + +TEST_F(Test_LoRaMacCommand, clear_sticky_mac_cmd) +{ + loramac_mlme_confirm_t mlme; + lora_mac_system_params_t params; + my_LoRaPHY phy; + uint8_t buf[20]; + + EXPECT_TRUE(object->has_sticky_mac_cmd() == false); + + object->clear_command_buffer(); + buf[0] = 5; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + EXPECT_TRUE(object->has_sticky_mac_cmd() == true); + + object->clear_sticky_mac_cmd(); + EXPECT_TRUE(object->has_sticky_mac_cmd() == false); +} + +TEST_F(Test_LoRaMacCommand, has_sticky_mac_cmd) +{ + loramac_mlme_confirm_t mlme; + lora_mac_system_params_t params; + my_LoRaPHY phy; + uint8_t buf[20]; + + EXPECT_TRUE(object->has_sticky_mac_cmd() == false); + + object->clear_command_buffer(); + buf[0] = 5; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + EXPECT_TRUE(object->has_sticky_mac_cmd() == true); +} + +TEST_F(Test_LoRaMacCommand, process_mac_commands) +{ + loramac_mlme_confirm_t mlme; + lora_mac_system_params_t params; + my_LoRaPHY phy; + uint8_t buf[20]; + EXPECT_TRUE(object->process_mac_commands(NULL, 0, 0, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 2; + buf[1] = 16; + buf[2] = 32; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 3, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + buf[0] = 3; + LoRaPHY_stub::uint8_value = 7; + LoRaPHY_stub::linkAdrNbBytesParsed = 5; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_link_adr_ans function here + object->clear_command_buffer(); + buf[0] = 3; + for (int i = 0; i < 64; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 4; + buf[1] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_duty_cycle_ans() + object->clear_command_buffer(); + for (int i = 0; i < 128; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 5; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_rx_param_setup_ans + object->clear_command_buffer(); + LoRaPHY_stub::uint8_value = 7; + for (int i = 0; i < 64; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 5, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 6; + object->set_batterylevel_callback(my_cb); + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //overflow add_dev_status_ans + object->clear_command_buffer(); + for (int i = 0; i < 42; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 7; + buf[1] = 2; + buf[2] = 2; + buf[3] = 2; + buf[4] = 2; + buf[5] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_new_channel_ans + object->clear_command_buffer(); + LoRaPHY_stub::uint8_value = 7; + for (int i = 0; i < 64; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 6, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 8; + buf[1] = 0; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_rx_timing_setup_ans + object->clear_command_buffer(); + LoRaPHY_stub::uint8_value = 7; + for (int i = 0; i < 128; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 9; + buf[1] = 48; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_tx_param_setup_ans + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + object->clear_command_buffer(); + LoRaPHY_stub::uint8_value = 7; + for (int i = 0; i < 128; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + LoRaPHY_stub::bool_counter = 0; + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 2, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 10; + buf[1] = 4; + buf[2] = 2; + buf[3] = 2; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + + //Overflow add_dl_channel_ans + object->clear_command_buffer(); + for (int i = 0; i < 64; i++) { + EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_OK); + } + EXPECT_TRUE(object->process_mac_commands(buf, 0, 4, 0, mlme, params, phy) == LORAWAN_STATUS_LENGTH_ERROR); + + object->clear_command_buffer(); + buf[0] = 80; + EXPECT_TRUE(object->process_mac_commands(buf, 0, 1, 0, mlme, params, phy) == LORAWAN_STATUS_UNSUPPORTED); +} + +TEST_F(Test_LoRaMacCommand, add_link_check_req) +{ + object->add_link_check_req(); + EXPECT_TRUE(object->get_mac_commands_buffer()[0] == 2); + EXPECT_TRUE(object->get_mac_cmd_length() == 1); + object->clear_command_buffer(); + EXPECT_TRUE(object->get_mac_cmd_length() == 0); +} + +TEST_F(Test_LoRaMacCommand, set_batterylevel_callback) +{ + object->set_batterylevel_callback(my_cb); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake new file mode 100644 index 0000000..a1929ec --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccommand/unittest.cmake @@ -0,0 +1,41 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaMacCommand") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/mac/LoRaMacCommand.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/mac +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loramaccommand/Test_LoRaMacCommand.cpp + stubs/mbed_assert_stub.cpp + stubs/LoRaPHY_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 +) diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp new file mode 100644 index 0000000..1c00938 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaMacCrypto.h" + +#include "cipher_stub.h" +#include "cmac_stub.h" +#include "aes_stub.h" + +class Test_LoRaMacCrypto : public testing::Test { +protected: + LoRaMacCrypto *object; + + virtual void SetUp() + { + cipher_stub.info_value = NULL; + cipher_stub.int_zero_counter = 0; + cipher_stub.int_value = 0; + cmac_stub.int_zero_counter = 0; + cmac_stub.int_value = 0; + aes_stub.int_zero_counter = 0; + aes_stub.int_value = 0; + object = new LoRaMacCrypto(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaMacCrypto, constructor) +{ + EXPECT_TRUE(object); + LoRaMacCrypto obj; +} + +TEST_F(Test_LoRaMacCrypto, compute_mic) +{ + EXPECT_TRUE(MBEDTLS_ERR_CIPHER_ALLOC_FAILED == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + mbedtls_cipher_info_t info; + cipher_stub.info_value = &info; + cipher_stub.int_zero_counter = 0; + cipher_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + cipher_stub.int_value = 0; + cmac_stub.int_zero_counter = 0; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + cmac_stub.int_zero_counter = 1; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + cmac_stub.int_zero_counter = 2; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + cmac_stub.int_zero_counter = 3; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + uint32_t mic[16]; + cmac_stub.int_zero_counter = 3; + cmac_stub.int_value = 0; + EXPECT_TRUE(0 == object->compute_mic(NULL, 0, NULL, 0, 0, 0, 0, mic)); + +} + +TEST_F(Test_LoRaMacCrypto, encrypt_payload) +{ + aes_stub.int_zero_counter = 0; + aes_stub.int_value = -1; + EXPECT_TRUE(-1 == object->encrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); + + aes_stub.int_zero_counter = 1; + aes_stub.int_value = -2; + uint8_t buf[60]; + uint8_t enc[60]; + EXPECT_TRUE(-2 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); + + aes_stub.int_zero_counter = 2; + aes_stub.int_value = -3; + EXPECT_TRUE(-3 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); + + aes_stub.int_value = 0; + EXPECT_TRUE(0 == object->encrypt_payload(buf, 20, NULL, 0, 0, 0, 0, enc)); + + EXPECT_TRUE(0 == object->encrypt_payload(buf, 60, NULL, 0, 0, 0, 0, enc)); + + aes_stub.int_zero_counter = 0; + EXPECT_TRUE(0 == object->encrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); +} + +TEST_F(Test_LoRaMacCrypto, decrypt_payload) +{ + EXPECT_TRUE(0 == object->decrypt_payload(NULL, 0, NULL, 0, 0, 0, 0, NULL)); +} + +TEST_F(Test_LoRaMacCrypto, compute_join_frame_mic) +{ + uint32_t mic[16]; + EXPECT_TRUE(MBEDTLS_ERR_CIPHER_ALLOC_FAILED == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); + mbedtls_cipher_info_t info; + cipher_stub.info_value = &info; + cipher_stub.int_zero_counter = 0; + cipher_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); + + cipher_stub.int_value = 0; + cmac_stub.int_zero_counter = 0; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); + + cmac_stub.int_zero_counter = 1; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); + + cmac_stub.int_zero_counter = 2; + cmac_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_join_frame_mic(NULL, 0, NULL, 0, NULL)); + + cmac_stub.int_zero_counter = 3; + cmac_stub.int_value = 0; + EXPECT_TRUE(0 == object->compute_join_frame_mic(NULL, 0, NULL, 0, mic)); +} + +TEST_F(Test_LoRaMacCrypto, decrypt_join_frame) +{ + aes_stub.int_zero_counter = 0; + aes_stub.int_value = -1; + EXPECT_TRUE(-1 == object->decrypt_join_frame(NULL, 0, NULL, 0, NULL)); + + aes_stub.int_zero_counter = 1; + aes_stub.int_value = -1; + EXPECT_TRUE(-1 == object->decrypt_join_frame(NULL, 0, NULL, 0, NULL)); + + aes_stub.int_value = 0; + uint8_t buf[60]; + uint8_t enc[60]; + EXPECT_TRUE(0 == object->decrypt_join_frame(buf, 60, NULL, 0, enc)); +} + +TEST_F(Test_LoRaMacCrypto, compute_skeys_for_join_frame) +{ + uint8_t nwk_key[16]; + uint8_t app_key[16]; + uint8_t nonce[16]; + + aes_stub.int_zero_counter = 0; + aes_stub.int_value = -1; + EXPECT_TRUE(-1 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); + + aes_stub.int_zero_counter = 1; + aes_stub.int_value = -2; + EXPECT_TRUE(-2 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); + + aes_stub.int_zero_counter = 0; + aes_stub.int_value = 0; + EXPECT_TRUE(0 == object->compute_skeys_for_join_frame(NULL, 0, nonce, 0, nwk_key, app_key)); +} diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake new file mode 100644 index 0000000..61aaae9 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loramaccrypto/unittest.cmake @@ -0,0 +1,45 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaMacCrypto") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/mac/LoRaMacCrypto.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/mac +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loramaccrypto/Test_LoRaMacCrypto.cpp + stubs/cipher_stub.c + stubs/aes_stub.c + stubs/cmac_stub.c + stubs/mbed_assert_stub.cpp + ../connectivity/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + ) diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp new file mode 100644 index 0000000..6220649 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/Test_LoRaPHY.cpp @@ -0,0 +1,944 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHY.h" + +#include "LoRaWANTimer_stub.h" + +class my_LoRaPHY : public LoRaPHY { +public: + my_LoRaPHY() + { + phy_params.adr_ack_delay = 1; + } + + 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 { +protected: + my_LoRaPHY *object; + + virtual void SetUp() + { + object = new my_LoRaPHY(); + memset(&object->get_phy_params(), 0, sizeof(object->get_phy_params())); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaPHY, initialize) +{ + 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; + p[0].dr_range.fields.min = DR_0; + p[0].dr_range.fields.max = DR_5; + object->get_phy_params().channels.channel_list = p; + 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->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; + buf = 0x08; + 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) +{ + 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; + //First 3 channels are set to be default + p.band = 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; + + //Default channel, PARAMETER invalid + EXPECT_TRUE(0 == object->request_new_channel(0, &p)); + + //Freq & DR invalid + p.frequency = 12345; + 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 + p.frequency = 12345; + p.dr_range.fields.max = DR_5; + object->get_phy_params().default_channel_cnt = 3; + EXPECT_TRUE(2 == object->request_new_channel(0, &p)); + + //DR invalid + p.frequency = 8687000; + 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 = DR_5; + p.dr_range.fields.min = DR_0; + uint16_t ch_msk = 0x08; + object->get_phy_params().channels.mask = &ch_msk; + 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]; + memset(list, 0, 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 = 1; + object->get_phy_params().cflist_channel_cnt = 0; + object->get_phy_params().max_channel_cnt = 3; + + uint16_t def_mask = 0x01; + channel_params_t p[16]; + memset(p, 0, 16); + //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->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; + memset(&p, 0, sizeof(rx_config_params_t)); + 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] = 125000; + object->get_phy_params().bandwidths.table = list; + uint8_t list2[1]; + list2[0] = 12; + 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; + memset(&p, 0, sizeof(rx_config_params_t)); + p.frequency = 8687000; + 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; + memset(&b, 0, sizeof(band_t)); + object->get_phy_params().bands.table = &b; + channel_params_t pp; + memset(&pp, 0, sizeof(channel_params_t)); + pp.band = 0; + object->get_phy_params().channels.channel_list = &pp; + uint32_t list[1]; + list[0] = 125000; + object->get_phy_params().bandwidths.table = &list; + uint8_t list2[1]; + list2[0] = 12; + object->get_phy_params().datarates.table = &list2; + my_radio radio; + object->set_radio_instance(radio); + tx_config_params_t p; + memset(&p, 0, sizeof(tx_config_params_t)); + p.channel = 0; + int8_t i = 20; + lorawan_time_t t = 36; + 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; + memset(&p, 0, sizeof(adr_req_params_t)); + uint8_t b[100]; + memset(b, 0, 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 = 0, j = 0; + uint8_t k = 0, l = 0; + uint8_t t[5] = {12, 11, 10, 9, 8}; + t[0] = 0; + object->get_phy_params().datarates.size = 5; + object->get_phy_params().datarates.table = t; + //Test without ADR payload does not make sense here. + + object->get_phy_params().max_channel_cnt = 16; + channel_params_t li[16]; + memset(li, 0, sizeof(channel_params_t) * 16); + 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_trans = 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; + radio.bool_value = true; + object->set_radio_instance(radio); + rx_param_setup_req_t 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) +{ + 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]; + 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; + 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; + + 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; + memset(&p, 0, sizeof(channel_selection_params_t)); + band_t band[1]; + 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; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&p, &ch, &t1, &t2)); + + uint16_t list[129]; + memset(list, 0, sizeof(list)); + list[4] = 1; + list[128] = 1; + object->get_phy_params().channels.mask = list; + object->get_phy_params().channels.default_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]; + ch = 5; + t1 = 16; + t2 = 32; + memset(b, 0, sizeof(band_t) * 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; + memset(list, 0, 129); + list[4] = 0; + object->get_phy_params().channels.mask = list; + object->get_phy_params().channels.default_mask = list; + 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; + p.band = 0; + p.frequency = 0; + 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; + b.max_tx_pwr = 10; + 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; + p.tx_power = -1; + p.datarate = 0; + p.antenna_gain = 1; + 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/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/unittest.cmake new file mode 100644 index 0000000..7566576 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphy/unittest.cmake @@ -0,0 +1,46 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHY") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHY.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphy/Test_LoRaPHY.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_WAKEUP_TIME=5 + -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_NB_TRIALS=2 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp new file mode 100644 index 0000000..47e9b76 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYAS923.h" + +#include "LoRaPHY_stub.h" + +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_LoRaPHYAS923 : public testing::Test { +protected: + LoRaPHYAS923 *object; + my_radio radio; + + virtual void SetUp() + { + LoRaPHY_stub::radio = &radio; + object = new LoRaPHYAS923(); + } + + virtual void TearDown() + { + LoRaPHY_stub::radio = NULL; + delete object; + } +}; + +TEST_F(Test_LoRaPHYAS923, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYAS923, get_alternate_DR) +{ + EXPECT_TRUE(2 == object->get_alternate_DR(1)); +} + +TEST_F(Test_LoRaPHYAS923, set_next_channel) +{ + channel_selection_params_t next_channel; + lorawan_time_t backoff_time = 0; + lorawan_time_t time = 0; + uint8_t ch = 1; + + next_channel.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + next_channel.aggregate_timeoff = 1; + radio.bool_value = false; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + next_channel.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 1; + EXPECT_TRUE(LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + radio.bool_value = true; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); +} + +TEST_F(Test_LoRaPHYAS923, apply_DR_offset) +{ + //0, 1, 2, 3, 4, 5, -1, -2 + for (int i = 0; i < 8; i++) { + uint8_t val = i > 5 ? 5 : 2; + EXPECT_TRUE(object->apply_DR_offset(0, i)); + } +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake new file mode 100644 index 0000000..723ade1 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyas923/unittest.cmake @@ -0,0 +1,46 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYAS923") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYAS923.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyas923/Test_LoRaPHYAS923.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp new file mode 100644 index 0000000..93ff3d2 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYAU915.h" + +#include "LoRaPHY_stub.h" + +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_LoRaPHYAU915 : public testing::Test { +protected: + LoRaPHYAU915 *object; + my_radio radio; + + virtual void SetUp() + { + LoRaPHY_stub::radio = &radio; + object = new LoRaPHYAU915(); + } + + virtual void TearDown() + { + LoRaPHY_stub::radio = NULL; + delete object; + } +}; + +TEST_F(Test_LoRaPHYAU915, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYAU915, rx_config) +{ + rx_config_params_t p; + memset(&p, 0, sizeof(p)); + + radio.uint8_value = 1; + EXPECT_TRUE(!object->rx_config(&p)); + + radio.uint8_value = 0; + p.is_repeater_supported = true; + EXPECT_TRUE(object->rx_config(&p)); + + p.is_repeater_supported = false; + EXPECT_TRUE(object->rx_config(&p)); +} + +TEST_F(Test_LoRaPHYAU915, tx_config) +{ + tx_config_params_t p; + memset(&p, 0, sizeof(p)); + int8_t tx = 0; + lorawan_time_t time; + p.tx_power = 9; + EXPECT_TRUE(object->tx_config(&p, &tx, &time)); +} + +TEST_F(Test_LoRaPHYAU915, link_ADR_request) +{ + adr_req_params_t params; + memset(¶ms, 0, sizeof(params)); + int8_t dr_out = 0; + int8_t tx_power_out = 0; + uint8_t nb_rep_out = 0; + uint8_t nb_bytes_parsed = 0; + + uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; + params.payload = payload; + params.payload_size = 5; + + LoRaPHY_stub::uint8_value = 1; + LoRaPHY_stub::ch_mask_value = 6; + LoRaPHY_stub::adr_parse_count = 2; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 7; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 5; + LoRaPHY_stub::uint8_value = 6; + EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 66; + LoRaPHY_stub::uint8_value = 7; + EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); +} + +TEST_F(Test_LoRaPHYAU915, accept_rx_param_setup_req) +{ + rx_param_setup_req_t p; + memset(&p, 0, sizeof(p)); + radio.bool_value = false; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 923300000 - 1; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 927500000 + 1; + p.datarate = 6; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 923300000 + 600000; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + LoRaPHY_stub::bool_table[1] = true; + EXPECT_TRUE(7 == object->accept_rx_param_setup_req(&p)); +} + +TEST_F(Test_LoRaPHYAU915, get_alternate_DR) +{ + EXPECT_TRUE(0 == object->get_alternate_DR(0)); + + EXPECT_TRUE(6 == object->get_alternate_DR(1)); +} + +TEST_F(Test_LoRaPHYAU915, set_next_channel) +{ + channel_selection_params_t params; + uint8_t channel; + lorawan_time_t time; + lorawan_time_t timeoff; + + params.current_datarate = 6; + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + radio.bool_value = false; + params.aggregate_timeoff = 1; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 1; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); +} + +TEST_F(Test_LoRaPHYAU915, apply_DR_offset) +{ +// { DR_8, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_0 +// { DR_9, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_1 +// { DR_10, DR_9, DR_8, DR_8, DR_8, DR_8 }, // DR_2 +// { DR_11, DR_10, DR_9, DR_8, DR_8, DR_8 }, // DR_3 +// { DR_12, DR_11, DR_10, DR_9, DR_8, DR_8 }, // DR_4 +// { DR_13, DR_12, DR_11, DR_10, DR_9, DR_8 }, // DR_5 +// { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6 + + for (int i = 0; i < 7; i++) { + for (int j = 0; j < 6; j++) { + uint8_t val = 8 + i; + val -= j; + if (val > 13) { + val = 13; + } + if (val < 8) { + val = 8; + } + EXPECT_TRUE(val == object->apply_DR_offset(i, j)); + } + } +} diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake new file mode 100644 index 0000000..93c12ac --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyau915/unittest.cmake @@ -0,0 +1,50 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYAU915") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyau915/Test_LoRaPHYAU915.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp new file mode 100644 index 0000000..20e8fc3 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYCN470.h" + +#include "LoRaPHY_stub.h" + +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_LoRaPHYCN470 : public testing::Test { +protected: + LoRaPHYCN470 *object; + my_radio radio; + + virtual void SetUp() + { + + LoRaPHY_stub::radio = &radio; + object = new LoRaPHYCN470(); + } + + virtual void TearDown() + { + + LoRaPHY_stub::radio = NULL; + delete object; + } +}; + +TEST_F(Test_LoRaPHYCN470, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYCN470, set_next_channel) +{ + channel_selection_params_t params; + + memset(¶ms, 0, sizeof(params)); + uint8_t channel = 0; + lorawan_time_t time = 0; + lorawan_time_t timeoff = 0; + + params.current_datarate = 4; + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + radio.bool_value = false; + params.aggregate_timeoff = 1; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 1; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); +} + +TEST_F(Test_LoRaPHYCN470, rx_config) +{ + rx_config_params_t p; + memset(&p, 0, sizeof(p)); + + radio.uint8_value = 1; + EXPECT_TRUE(!object->rx_config(&p)); + + radio.uint8_value = 0; + p.is_repeater_supported = true; + EXPECT_TRUE(object->rx_config(&p)); + + p.is_repeater_supported = false; + EXPECT_TRUE(object->rx_config(&p)); +} + +TEST_F(Test_LoRaPHYCN470, tx_config) +{ + tx_config_params_t p; + memset(&p, 0, sizeof(p)); + int8_t tx = 0; + lorawan_time_t time = 0; + p.tx_power = 9; + EXPECT_TRUE(object->tx_config(&p, &tx, &time)); +} + +TEST_F(Test_LoRaPHYCN470, link_ADR_request) +{ + adr_req_params_t params; + memset(¶ms, 0, sizeof(params)); + int8_t dr_out = 0; + int8_t tx_power_out = 0; + uint8_t nb_rep_out = 0; + uint8_t nb_bytes_parsed = 0; + + uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; + params.payload = payload; + params.payload_size = 5; + + LoRaPHY_stub::uint8_value = 1; + LoRaPHY_stub::ch_mask_value = 6; + LoRaPHY_stub::adr_parse_count = 2; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 7; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 5; + LoRaPHY_stub::uint8_value = 6; + EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 66; + LoRaPHY_stub::uint8_value = 7; + EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); +} + +TEST_F(Test_LoRaPHYCN470, accept_rx_param_setup_req) +{ + rx_param_setup_req_t p; + memset(&p, 0, sizeof(p)); + radio.bool_value = false; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 923300000 - 1; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 927500000 + 1; + p.datarate = 6; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); +} + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake new file mode 100644 index 0000000..910ba9a --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn470/unittest.cmake @@ -0,0 +1,49 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYCN470") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYCN470.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphycn470/Test_LoRaPHYCN470.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp new file mode 100644 index 0000000..0d729b4 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYCN779.h" + +class Test_LoRaPHYCN779 : public testing::Test { +protected: + LoRaPHYCN779 *object; + + virtual void SetUp() + { + object = new LoRaPHYCN779(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaPHYCN779, constructor) +{ + EXPECT_TRUE(object); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake new file mode 100644 index 0000000..66c11e2 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphycn779/unittest.cmake @@ -0,0 +1,47 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYCN779") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYCN779.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphycn779/Test_LoRaPHYCN779.cpp + stubs/LoRaPHY_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK_CHINA=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp new file mode 100644 index 0000000..1981943 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYEU433.h" + +class Test_LoRaPHYEU433 : public testing::Test { +protected: + LoRaPHYEU433 *object; + + virtual void SetUp() + { + object = new LoRaPHYEU433(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaPHYEU433, constructor) +{ + EXPECT_TRUE(object); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake new file mode 100644 index 0000000..ffafac6 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu433/unittest.cmake @@ -0,0 +1,45 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYEU433") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYEU433.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyeu433/Test_LoRaPHYEU433.cpp + stubs/LoRaPHY_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp new file mode 100644 index 0000000..f216c12 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYEU868.h" + +class Test_LoRaPHYEU868 : public testing::Test { +protected: + LoRaPHYEU868 *object; + + virtual void SetUp() + { + object = new LoRaPHYEU868(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaPHYEU868, constructor) +{ + EXPECT_TRUE(object); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake new file mode 100644 index 0000000..009eb04 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyeu868/unittest.cmake @@ -0,0 +1,45 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYEU868") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYEU868.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyeu868/Test_LoRaPHYEU868.cpp + stubs/LoRaPHY_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp new file mode 100644 index 0000000..ecb1211 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYIN865.h" + +class Test_LoRaPHYIN865 : public testing::Test { +protected: + LoRaPHYIN865 *object; + + virtual void SetUp() + { + object = new LoRaPHYIN865(); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaPHYIN865, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYIN865, apply_DR_offset) +{ + EXPECT_TRUE(0 == object->apply_DR_offset(0, 0)); +} + + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake new file mode 100644 index 0000000..1ba6039 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyin865/unittest.cmake @@ -0,0 +1,45 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYIN865") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYIN865.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyin865/Test_LoRaPHYIN865.cpp + stubs/LoRaPHY_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp new file mode 100644 index 0000000..5a170a1 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYKR920.h" +#include "LoRaPHY_stub.h" +#include "LoRaRadio.h" + +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) + { + }; + + 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; +}; + +class Test_LoRaPHYKR920 : public testing::Test { +protected: + LoRaPHYKR920 *object; + my_radio radio; + + virtual void SetUp() + { + LoRaPHY_stub::radio = &radio; + object = new LoRaPHYKR920(); + } + + virtual void TearDown() + { + LoRaPHY_stub::radio = NULL; + delete object; + } +}; + +TEST_F(Test_LoRaPHYKR920, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYKR920, verify_frequency_for_band) +{ + radio.bool_value = false; + EXPECT_TRUE(false == object->verify_frequency_for_band(0, 0)); + + radio.bool_value = true; + EXPECT_TRUE(false == object->verify_frequency_for_band(0, 0)); + + EXPECT_TRUE(true == object->verify_frequency_for_band(921100000, 0)); +} + +TEST_F(Test_LoRaPHYKR920, tx_config) +{ + tx_config_params_t tx_config; + memset(&tx_config, 0, sizeof(tx_config)); + int8_t tx_power = 0; + lorawan_time_t time = 0; + + tx_config.tx_power = 9; + EXPECT_TRUE(true == object->tx_config(&tx_config, &tx_power, &time)); +} + +TEST_F(Test_LoRaPHYKR920, set_next_channel) +{ + channel_selection_params_t next_channel; + memset(&next_channel, 0, sizeof(next_channel)); + lorawan_time_t backoff_time = 0; + lorawan_time_t time = 0; + uint8_t ch = 1; + + next_channel.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + next_channel.aggregate_timeoff = 1; + radio.bool_value = false; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + next_channel.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 1; + EXPECT_TRUE(LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); + + radio.bool_value = true; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(&next_channel, &ch, &backoff_time, &time)); +} + +TEST_F(Test_LoRaPHYKR920, set_tx_cont_mode) +{ + cw_mode_params_t params; + memset(¶ms, 0, sizeof(params)); + params.tx_power = 9; + object->set_tx_cont_mode(¶ms, 0); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake new file mode 100644 index 0000000..a34e3aa --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphykr920/unittest.cmake @@ -0,0 +1,46 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYKR920") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYKR920.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphykr920/Test_LoRaPHYKR920.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp new file mode 100644 index 0000000..82d9e7b --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaPHYUS915.h" +#include "LoRaPHY_stub.h" + + +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_LoRaPHYUS915 : public testing::Test { +protected: + LoRaPHYUS915 *object; + my_radio radio; + + virtual void SetUp() + { + LoRaPHY_stub::radio = &radio; + object = new LoRaPHYUS915(); + } + + virtual void TearDown() + { + LoRaPHY_stub::radio = NULL; + delete object; + } +}; + +TEST_F(Test_LoRaPHYUS915, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaPHYUS915, restore_default_channels) +{ + object->restore_default_channels(); +} + +TEST_F(Test_LoRaPHYUS915, rx_config) +{ + rx_config_params_t p; + memset(&p, 0, sizeof(p)); + + radio.uint8_value = 1; + EXPECT_TRUE(!object->rx_config(&p)); + + radio.uint8_value = 0; + p.is_repeater_supported = true; + EXPECT_TRUE(object->rx_config(&p)); + + p.is_repeater_supported = false; + EXPECT_TRUE(object->rx_config(&p)); +} + +TEST_F(Test_LoRaPHYUS915, tx_config) +{ + tx_config_params_t p; + memset(&p, 0, sizeof(p)); + int8_t tx = 0; + lorawan_time_t time = 0; + EXPECT_TRUE(object->tx_config(&p, &tx, &time)); +} + +TEST_F(Test_LoRaPHYUS915, link_ADR_request) +{ + uint8_t payload [] = {SRV_MAC_LINK_ADR_REQ, 1, 2, 3, 4}; + adr_req_params_t params; + memset(¶ms, 0, sizeof(params)); + int8_t dr_out = 0; + int8_t tx_power_out = 0; + uint8_t nb_rep_out = 0; + uint8_t nb_bytes_parsed = 0; + + params.payload = payload; + params.payload_size = 4; + + uint8_t status = object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed); + + EXPECT_TRUE(0 == nb_bytes_parsed); + + params.payload_size = 5; + LoRaPHY_stub::uint8_value = 1; + LoRaPHY_stub::ch_mask_value = 6; + LoRaPHY_stub::adr_parse_count = 2; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 7; + EXPECT_TRUE(1 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 5; + LoRaPHY_stub::uint8_value = 6; + EXPECT_TRUE(6 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); + + LoRaPHY_stub::adr_parse_count = 2; + LoRaPHY_stub::ch_mask_value = 66; + LoRaPHY_stub::uint8_value = 7; + EXPECT_TRUE(7 == object->link_ADR_request(¶ms, &dr_out, &tx_power_out, &nb_rep_out, &nb_bytes_parsed)); +} + +TEST_F(Test_LoRaPHYUS915, accept_rx_param_setup_req) +{ + rx_param_setup_req_t p; + memset(&p, 0, sizeof(p)); + radio.bool_value = false; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 923300000 - 1; + EXPECT_TRUE(0 == object->accept_rx_param_setup_req(&p)); + + radio.bool_value = true; + p.frequency = 927500000 + 1; + p.datarate = 6; + LoRaPHY_stub::bool_counter = 0; + LoRaPHY_stub::bool_table[0] = true; + EXPECT_TRUE(2 == object->accept_rx_param_setup_req(&p)); +} + +TEST_F(Test_LoRaPHYUS915, get_alternate_DR) +{ + EXPECT_TRUE(0 == object->get_alternate_DR(0)); + + EXPECT_TRUE(4 == object->get_alternate_DR(1)); +} + +TEST_F(Test_LoRaPHYUS915, set_next_channel) +{ + channel_selection_params_t params; + memset(¶ms, 0, sizeof(params)); + uint8_t channel = 0; + lorawan_time_t time = 0; + lorawan_time_t timeoff = 0; + + params.current_datarate = 4; + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_NO_CHANNEL_FOUND == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + radio.bool_value = false; + params.aggregate_timeoff = 1; + EXPECT_TRUE(LORAWAN_STATUS_DUTYCYCLE_RESTRICTED == object->set_next_channel(¶ms, &channel, &time, &timeoff)); + + params.aggregate_timeoff = 0; + LoRaPHY_stub::uint8_value = 1; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_next_channel(¶ms, &channel, &time, &timeoff)); +} + +TEST_F(Test_LoRaPHYUS915, apply_DR_offset) +{ + //10, 9, 8, 8 + //11, 10, 9, 8 + //12, 11, 10, 9 + //13, 12, 11, 10 + //13, 13, 12, 11 + + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 4; j++) { + uint8_t val = 10 + i; + val -= j; + if (val > 13) { + val = 13; + } + if (val < 8) { + val = 8; + } + EXPECT_TRUE(val == object->apply_DR_offset(i, j)); + } + } +} + +TEST_F(Test_LoRaPHYUS915, set_tx_cont_mode) +{ + cw_mode_params_t p; + memset(&p, 0, sizeof(p)); + object->set_tx_cont_mode(&p, 0); + + p.datarate = 4; + object->set_tx_cont_mode(&p, 0); +} diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake new file mode 100644 index 0000000..d68bca9 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/loraphyus915/unittest.cmake @@ -0,0 +1,48 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaPHYUS915") + +# Source files +set(unittest-sources + ../features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/lorastack/phy +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/loraphyus915/Test_LoRaPHYUS915.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/mbed_assert_stub.cpp + +) + +set(unittest-test-flags + -DMBED_CONF_LORA_TX_MAX_SIZE=255 + -DMBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH=5 + -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_FSB_MASK=\"{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}\"") diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp new file mode 100644 index 0000000..f4506a8 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaWANInterface.h" + +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) + { + }; + + 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) + { + }; + + virtual void start_cad(void) + { + }; + + virtual bool check_rf_frequency(uint32_t frequency) + { + }; + + virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time) + { + }; + + virtual void lock(void) + { + }; + + virtual void unlock(void) + { + }; +}; + +class my_LoRaPHY : public LoRaPHY { +public: + my_LoRaPHY() + { + }; + + virtual ~my_LoRaPHY() + { + }; +}; + +class Test_LoRaWANInterface : public testing::Test { +protected: + LoRaWANInterface *object; + my_radio radio; + + virtual void SetUp() + { + object = new LoRaWANInterface(radio); + } + + virtual void TearDown() + { + delete object; + } +}; + +TEST_F(Test_LoRaWANInterface, constructor) +{ + EXPECT_TRUE(object); + + my_radio radio; + my_LoRaPHY phy; + LoRaWANInterface object(radio, phy); +} + +TEST_F(Test_LoRaWANInterface, initialize) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize(NULL)); +} + +TEST_F(Test_LoRaWANInterface, connect) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect()); + + lorawan_connect_t conn; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); +} + +TEST_F(Test_LoRaWANInterface, disconnect) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->disconnect()); +} + +TEST_F(Test_LoRaWANInterface, add_link_check_request) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_link_check_request()); +} + +TEST_F(Test_LoRaWANInterface, remove_link_check_request) +{ + object->remove_link_check_request(); +} + +TEST_F(Test_LoRaWANInterface, set_datarate) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_datarate(1)); +} + +TEST_F(Test_LoRaWANInterface, enable_adaptive_datarate) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->enable_adaptive_datarate()); +} + +TEST_F(Test_LoRaWANInterface, disable_adaptive_datarate) +{ + object->disable_adaptive_datarate(); +} + +TEST_F(Test_LoRaWANInterface, set_confirmed_msg_retries) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_confirmed_msg_retries(1)); +} + +TEST_F(Test_LoRaWANInterface, set_channel_plan) +{ + lorawan_channelplan_t plan; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_channel_plan(plan)); +} + +TEST_F(Test_LoRaWANInterface, get_channel_plan) +{ + lorawan_channelplan_t plan; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_channel_plan(plan)); +} + +TEST_F(Test_LoRaWANInterface, remove_channel_plan) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_channel_plan()); +} + +TEST_F(Test_LoRaWANInterface, remove_channel) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_channel(1)); +} + +TEST_F(Test_LoRaWANInterface, send) +{ + EXPECT_TRUE(0 == object->send(1, NULL, 0, 0)); +} + +TEST_F(Test_LoRaWANInterface, receive) +{ + EXPECT_TRUE(0 == object->receive(1, NULL, 0, 0)); + + uint8_t port; + int flags; + EXPECT_TRUE(0 == object->receive(NULL, 0, port, flags)); +} + +TEST_F(Test_LoRaWANInterface, add_app_callbacks) +{ + lorawan_app_callbacks_t cbs; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_app_callbacks(&cbs)); +} + +TEST_F(Test_LoRaWANInterface, set_device_class) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A)); +} + +TEST_F(Test_LoRaWANInterface, get_tx_metadata) +{ + lorawan_tx_metadata data; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_tx_metadata(data)); +} + +TEST_F(Test_LoRaWANInterface, get_rx_metadata) +{ + lorawan_rx_metadata data; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_rx_metadata(data)); +} + +TEST_F(Test_LoRaWANInterface, get_backoff_metadata) +{ + int i; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->get_backoff_metadata(i)); +} + +TEST_F(Test_LoRaWANInterface, cancel_sending) +{ + EXPECT_TRUE(LORAWAN_STATUS_OK == object->cancel_sending()); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake new file mode 100644 index 0000000..0db5b7a --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawaninterface/unittest.cmake @@ -0,0 +1,53 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaWANInterface") + +# Source files +set(unittest-sources + ../features/lorawan/LoRaWANInterface.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/lorawaninterface/Test_LoRaWANInterface.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaWANStack_stub.cpp + stubs/LoRaMac_stub.cpp + stubs/mbed_assert_stub.cpp + stubs/LoRaMacCrypto_stub.cpp + stubs/LoRaMacChannelPlan_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/LoRaMacCommand_stub.cpp + stubs/LoRaPHYEU868_stub.cpp + stubs/Mutex_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_PHY=EU868 + -DMBED_CONF_LORA_TX_MAX_SIZE=255 +) + + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp new file mode 100644 index 0000000..9fc72b1 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/Test_LoRaWANStack.cpp @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaWANStack.h" +#include "events/EventQueue.h" + +#include "LoRaPHY_stub.h" +#include "LoRaMac_stub.h" +#include "equeue_stub.h" +#include "lorawan_data_structures.h" + +static uint8_t batt_level = 0; + +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: + radio_events_t *_ev; + + virtual void init_radio(radio_events_t *events) + { + _ev = 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: + LoRaWANStack *object; + + virtual void SetUp() + { + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + object = new LoRaWANStack(); + } + + virtual void TearDown() + { + delete object; + } +}; + +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)); + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + //Visit callback + if (LoRaMac_stub::_scheduling_failure_handler) { + LoRaMac_stub::_scheduling_failure_handler.call(); + } +} + +void events_cb(lorawan_event_t ev) +{ + +} + +void lc_resp(uint8_t a, uint8_t b) +{ + +} + +uint8_t batt_lvl() +{ + return batt_level; +} + +TEST_F(Test_LoRaWANStack, set_lora_callbacks) +{ + lorawan_app_callbacks_t cb; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_lora_callbacks(&cb)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_lora_callbacks(NULL)); + + cb.events = NULL; + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_lora_callbacks(&cb)); + + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); +} + +TEST_F(Test_LoRaWANStack, connect) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect()); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; + EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect()); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect()); + + //_ctrl_flags & CONN_IN_PROGRESS_FLAG + EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect()); + + my_radio radio; + my_LoRaPHY 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_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = true; + mlme.req_type = MLME_JOIN; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_value = false; + radio._ev->rx_done(NULL, 0, 0, 0); + + //_ctrl_flags & CONNECTED_FLAG + EXPECT_TRUE(LORAWAN_STATUS_ALREADY_CONNECTED == object->connect()); + + //Visit rx_interrupt_handler's first if + radio._ev->rx_done(NULL, 65535, 0, 0); +} + +TEST_F(Test_LoRaWANStack, connect_args) +{ + lorawan_connect_t conn; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->connect(conn)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + conn.connect_type = lorawan_connect_type_t(8); + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->connect(conn)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; + conn.connect_type = LORAWAN_CONNECTION_OTAA; + EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect(conn)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); + + //_ctrl_flags & CONN_IN_PROGRESS_FLAG + EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->connect(conn)); + + object->shutdown(); + conn.connect_type = LORAWAN_CONNECTION_ABP; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); + + //_ctrl_flags & CONNECTED_FLAG + EXPECT_TRUE(LORAWAN_STATUS_ALREADY_CONNECTED == object->connect(conn)); +} + +TEST_F(Test_LoRaWANStack, add_channels) +{ + lorawan_channelplan_t plan; + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->add_channels(plan)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->add_channels(plan)); +} + +TEST_F(Test_LoRaWANStack, remove_a_channel) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->remove_a_channel(1)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->remove_a_channel(1)); +} + +TEST_F(Test_LoRaWANStack, drop_channel_list) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->drop_channel_list()); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_confirmed_msg_retry(255)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_channel_data_rate(4)); +} + +TEST_F(Test_LoRaWANStack, enable_adaptive_datarate) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->enable_adaptive_datarate(false)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_tx(0, NULL, 0, 0, false, false)); + + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + 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_link_check_request()); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_NO_ACTIVE_SESSIONS == object->handle_tx(0, NULL, 0, 0, true, false)); + + lorawan_connect_t conn; + conn.connect_type = LORAWAN_CONNECTION_ABP; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); + + LoRaMac_stub::bool_value = false; + EXPECT_TRUE(LORAWAN_STATUS_NO_NETWORK_JOINED == object->handle_tx(0, NULL, 0, 0, true, false)); + + LoRaMac_stub::bool_value = true; + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_tx(0, NULL, 0, 0, true, false)); + + LoRaMac_stub::bool_false_counter = 1; + LoRaMac_stub::bool_value = true; + //set_application_port fails + EXPECT_TRUE(LORAWAN_STATUS_PORT_INVALID == object->handle_tx(0, NULL, 0, 0, true, false)); + + LoRaMac_stub::bool_false_counter = 1; + LoRaMac_stub::bool_value = true; + //Wrong flags -> LORAWAN_STATUS_PARAMETER_INVALID + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_tx(1, NULL, 0, 0x04, true, false)); + + LoRaMac_stub::bool_false_counter = 1; + //Actual sending + EXPECT_TRUE(LORAWAN_STATUS_OK == object->handle_tx(1, NULL, 0, 0x08, 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + 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; + conn.connect_type = LORAWAN_CONNECTION_ABP; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->connect(conn)); + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(NULL, 0, port, flags, false)); + + //Prepare ready for receive state + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); + + my_radio radio; + my_LoRaPHY phy; + object->bind_phy_and_radio_driver(radio, phy); + + loramac_mcps_confirm_t conf; + conf.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + ind.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = false; + mlme.req_type = MLME_JOIN; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_value = true; + conf.req_type = MCPS_PROPRIETARY; + + ind.pending = true; + LoRaMac_stub::dev_class_value = CLASS_A; + + loramac_mlme_indication_t mlme_ind; + mlme_ind.pending = false; + LoRaMac_stub::mlme_ind_ptr = &mlme_ind; + + uint8_t ind_buf[150]; + for (int i = 0; i < 110; i++) { + ind_buf[i] = i; + } + ind.buffer = ind_buf; + ind.buffer_size = 150; + ind.type = MCPS_UNCONFIRMED; + ind.port = 15; + ind.is_data_recvd = true; + ind.fpending_status = false; + LoRaMac_stub::dev_class_value = CLASS_A; + radio._ev->rx_done(NULL, 0, 0, 0); + + //data == NULL || LENGTH == 0 (2 cases) + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_rx(NULL, 0, port, flags, false)); + uint8_t data[50]; + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->handle_rx(data, 0, port, flags, false)); + + //validate_params returns Would block + port = 43; + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); + + ind.type = MCPS_CONFIRMED; + radio._ev->rx_done(NULL, 0, 0, 0); + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); + //Call again to visit send_automatic_uplink_message error case + LoRaMac_stub::bool_true_counter = 1; + ind.type = MCPS_CONFIRMED; + ind.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + LoRaMac_stub::bool_value = false; + radio._ev->rx_done(NULL, 0, 0, 0); + + ind.status = LORAMAC_EVENT_INFO_STATUS_OK; + + LoRaMac_stub::bool_value = true; + //convert_to_msg_flag cases + ind.fpending_status = true; + ind.type = MCPS_PROPRIETARY; + radio._ev->rx_done(NULL, 0, 0, 0); + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); + + ind.type = MCPS_MULTICAST; + radio._ev->rx_done(NULL, 0, 0, 0); + EXPECT_TRUE(LORAWAN_STATUS_WOULD_BLOCK == object->handle_rx(data, 50, port, flags, true)); + + ind.type = MCPS_UNCONFIRMED; + radio._ev->rx_done(NULL, 0, 0, 0); + + //read not complete + EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); + EXPECT_EQ(10, data[10]); + + EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); + EXPECT_EQ(60, data[10]); + + //read complete + EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); + EXPECT_EQ(100, data[0]); + + //read can fit the buffer + for (int i = 0; i < 110; i++) { + ind_buf[i] = i; + } + ind.buffer = ind_buf; + ind.buffer_size = 50; + ind.type = mcps_type_t(66); + radio._ev->rx_done(NULL, 0, 0, 0); + EXPECT_TRUE(50 == object->handle_rx(data, 50, port, flags, false)); + EXPECT_EQ(10, data[10]); +} + +TEST_F(Test_LoRaWANStack, set_link_check_request) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_link_check_request()); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_PARAMETER_INVALID == object->set_link_check_request()); + + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); + EXPECT_TRUE(LORAWAN_STATUS_OK == 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()); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + EXPECT_TRUE(LORAWAN_STATUS_DEVICE_OFF == object->shutdown()); +} + +TEST_F(Test_LoRaWANStack, set_device_class) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->set_device_class(CLASS_A)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_UNSUPPORTED == object->set_device_class(CLASS_B)); + + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_device_class(CLASS_A)); +} + +TEST_F(Test_LoRaWANStack, acquire_tx_metadata) +{ + lorawan_tx_metadata data; + memset(&data, 0, sizeof(data)); + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_tx_metadata(data)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + // stale = true; + EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_tx_metadata(data)); + + // stale = false; + my_radio radio; + my_LoRaPHY 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; + memset(&conf, 0, sizeof(conf)); + conf.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mcps_conf_ptr = &conf; + 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)); +} + +TEST_F(Test_LoRaWANStack, acquire_rx_metadata) +{ + lorawan_rx_metadata data; + memset(&data, 0, sizeof(data)); + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->acquire_rx_metadata(data)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + // stale = true; + EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_rx_metadata(data)); + + // stale = false; + my_radio radio; + my_LoRaPHY 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; + memset(&conf, 0, sizeof(conf)); + conf.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = true; + mlme.req_type = MLME_JOIN; + + //Visit mlme_confirm_handler here also + mlme.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + LoRaMac_stub::bool_value = false; + radio._ev->rx_done(NULL, 0, 0, 0); + + mlme.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + radio._ev->rx_done(NULL, 0, 0, 0); + + mlme.status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; + LoRaMac_stub::slot_value = RX_SLOT_WIN_2; + radio._ev->rx_done(NULL, 0, 0, 0); + + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); + mlme.req_type = MLME_LINK_CHECK; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_true_counter = true; + radio._ev->rx_done(NULL, 0, 0, 0); + + EXPECT_TRUE(LORAWAN_STATUS_OK == 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)); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::int_value = 2; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->acquire_backoff_metadata(b)); + + LoRaMac_stub::int_value = 0; + EXPECT_TRUE(LORAWAN_STATUS_METADATA_NOT_AVAILABLE == object->acquire_backoff_metadata(b)); +} + +TEST_F(Test_LoRaWANStack, stop_sending) +{ + EXPECT_TRUE(LORAWAN_STATUS_NOT_INITIALIZED == object->stop_sending()); + + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + LoRaMac_stub::status_value = LORAWAN_STATUS_BUSY; + EXPECT_TRUE(LORAWAN_STATUS_BUSY == object->stop_sending()); + + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->stop_sending()); +} + +TEST_F(Test_LoRaWANStack, lock) +{ + object->lock(); +} + +TEST_F(Test_LoRaWANStack, unlock) +{ + object->unlock(); +} + +TEST_F(Test_LoRaWANStack, interrupt_functions) +{ + lorawan_connect_t conn; + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + my_radio radio; + my_LoRaPHY 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_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = true; + mlme.req_type = MLME_JOIN; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_value = false; + radio._ev->rx_done(NULL, 0, 0, 0); + + radio._ev->rx_done(NULL, 0, 0, 0); + + radio._ev->rx_error(); + LoRaMac_stub::slot_value = RX_SLOT_WIN_2; + radio._ev->rx_error(); + + conf.req_type = MCPS_UNCONFIRMED; + LoRaMac_stub::bool_value = true; + radio._ev->rx_error(); + + conf.req_type = MCPS_CONFIRMED; + radio._ev->rx_error(); + + LoRaMac_stub::bool_value = false; + + LoRaMac_stub::slot_value = RX_SLOT_WIN_1; + radio._ev->rx_timeout(); + + radio._ev->tx_timeout(); + + object->shutdown(); + conn.connect_type = LORAWAN_CONNECTION_OTAA; + object->connect(conn); + LoRaMac_stub::status_value = LORAWAN_STATUS_OK; + object->connect(conn); + radio._ev->tx_timeout(); +} + +TEST_F(Test_LoRaWANStack, process_transmission) +{ + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); + + my_radio radio; + my_LoRaPHY phy; + object->bind_phy_and_radio_driver(radio, phy); + + object->connect(); + + struct equeue_event ptr; + equeue_stub.void_ptr = &ptr; + equeue_stub.call_cb_immediately = true; + loramac_mcps_confirm_t conf; + LoRaMac_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = true; + mlme.req_type = MLME_JOIN; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_value = false; + radio._ev->rx_done(NULL, 0, 0, 0); + + LoRaMac_stub::bool_value = true; + conf.req_type = MCPS_PROPRIETARY; + LoRaMac_stub::bool_false_counter = 1; + LoRaMac_stub::dev_class_value = CLASS_A; + object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); + radio._ev->tx_done(); + + LoRaMac_stub::bool_false_counter = 1; + LoRaMac_stub::dev_class_value = CLASS_A; + object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); + radio._ev->tx_done(); + + LoRaMac_stub::bool_false_counter = 1; + LoRaMac_stub::dev_class_value = CLASS_C; + object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); + radio._ev->tx_done(); + + LoRaMac_stub::bool_false_counter = 1; + conf.req_type = MCPS_CONFIRMED; + object->handle_tx(1, NULL, 0, MSG_UNCONFIRMED_FLAG, true, false); + radio._ev->tx_done(); +} + +TEST_F(Test_LoRaWANStack, process_reception) +{ + EventQueue queue; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->initialize_mac_layer(&queue)); + + //Prepare ready for receive state + lorawan_app_callbacks_t cb; + cb.events = events_cb; + cb.link_check_resp = lc_resp; + cb.battery_level = batt_lvl; + EXPECT_TRUE(LORAWAN_STATUS_OK == object->set_lora_callbacks(&cb)); + + my_radio radio; + my_LoRaPHY 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; + memset(&conf, 0, sizeof(&conf)); + LoRaMac_stub::mcps_conf_ptr = &conf; + radio._ev->tx_done(); + + loramac_mcps_indication_t ind; + memset(&ind, 0, sizeof(ind)); + LoRaMac_stub::mcps_ind_ptr = &ind; + + loramac_mlme_confirm_t mlme; + LoRaMac_stub::mlme_conf_ptr = &mlme; + mlme.pending = false; + mlme.req_type = MLME_JOIN; + mlme.status = LORAMAC_EVENT_INFO_STATUS_OK; + LoRaMac_stub::bool_value = true; + conf.req_type = MCPS_PROPRIETARY; + + ind.pending = true; + LoRaMac_stub::dev_class_value = CLASS_C; + + loramac_mlme_indication_t mlme_ind; + mlme_ind.pending = false; + LoRaMac_stub::mlme_ind_ptr = &mlme_ind; + + uint8_t ind_buf[150]; + for (int i = 0; i < 110; i++) { + ind_buf[i] = i; + } + ind.buffer = ind_buf; + ind.buffer_size = 150; + + //_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED + conf.req_type = MCPS_CONFIRMED; + conf.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + radio._ev->rx_done(NULL, 0, 0, 0); + + ind.is_ack_recvd = false; + LoRaMac_stub::bool_true_counter = 1; + LoRaMac_stub::bool_value = false; + LoRaMac_stub::slot_value = RX_SLOT_WIN_2; + conf.status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; + radio._ev->rx_done(NULL, 0, 0, 0); + + conf.req_type = MCPS_UNCONFIRMED; + LoRaMac_stub::dev_class_value = CLASS_A; + LoRaMac_stub::bool_true_counter++; + mlme_ind.pending = true; + mlme_ind.indication_type = MLME_SCHEDULE_UPLINK; + conf.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + radio._ev->rx_done(NULL, 0, 0, 0); + + ind.is_ack_recvd = true; + conf.req_type = MCPS_CONFIRMED; + conf.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + radio._ev->rx_done(NULL, 0, 0, 0); +} + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake new file mode 100644 index 0000000..cbedd9c --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawanstack/unittest.cmake @@ -0,0 +1,53 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaWANStack") + +# Source files +set(unittest-sources + ../features/lorawan/LoRaWANStack.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/lorawanstack/Test_LoRaWANStack.cpp + stubs/LoRaPHY_stub.cpp + stubs/LoRaMac_stub.cpp + stubs/mbed_assert_stub.cpp + stubs/mbed_atomic_stub.c + stubs/LoRaMacCrypto_stub.cpp + stubs/LoRaMacChannelPlan_stub.cpp + stubs/LoRaWANTimer_stub.cpp + stubs/LoRaMacCommand_stub.cpp + stubs/EventQueue_stub.cpp + stubs/equeue_stub.c + stubs/Mutex_stub.cpp +) + +set(unittest-test-flags + -DMBED_CONF_LORA_OVER_THE_AIR_ACTIVATION=true + -DMBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE=true + -DMBED_CONF_LORA_TX_MAX_SIZE=255 +) + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp new file mode 100644 index 0000000..9fb10a3 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018, 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 "gtest/gtest.h" +#include "LoRaWANTimer.h" + +#include "equeue_stub.h" + +using namespace events; + +class Test_LoRaWANTimer : public testing::Test { +protected: + LoRaWANTimeHandler *object; + EventQueue *queue; + + virtual void SetUp() + { + queue = new EventQueue(3, NULL); + object = new LoRaWANTimeHandler(); + object->activate_timer_subsystem(queue); + } + + virtual void TearDown() + { + delete object; + delete queue; + } +}; + +TEST_F(Test_LoRaWANTimer, constructor) +{ + EXPECT_TRUE(object); +} + +TEST_F(Test_LoRaWANTimer, get_current_time) +{ + lorawan_time_t tt = object->get_current_time(); + EXPECT_TRUE(0 == tt); +} + +TEST_F(Test_LoRaWANTimer, get_elapsed_time) +{ + lorawan_time_t tt = object->get_elapsed_time(0); + EXPECT_TRUE(0 == tt); +} + +void my_callback() +{ +} + +TEST_F(Test_LoRaWANTimer, init) +{ + timer_event_t ev; + memset(&ev, 0, sizeof(ev)); + object->init(ev, my_callback); +} + +TEST_F(Test_LoRaWANTimer, start) +{ + equeue_stub.void_ptr = NULL; + timer_event_t ev; + memset(&ev, 0, sizeof(ev)); + object->start(ev, 10); +} + +TEST_F(Test_LoRaWANTimer, stop) +{ + timer_event_t ev; + memset(&ev, 0, sizeof(ev)); + ev.timer_id = 4; + object->stop(ev); + EXPECT_TRUE(ev.timer_id == 0); +} + + + diff --git a/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake new file mode 100644 index 0000000..b4ee1c9 --- /dev/null +++ b/connectivity/lorawan/tests/UNITTESTS/features/lorawan/lorawantimer/unittest.cmake @@ -0,0 +1,44 @@ +#[[ + * Copyright (c) 2018, 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. +]] + +# Unit test suite name +set(TEST_SUITE_NAME "lorawan_LoRaWANTimer") + +# Source files +set(unittest-sources + ../features/lorawan/system/LoRaWANTimer.cpp +) + +# Add test specific include paths +set(unittest-includes ${unittest-includes} + target_h + ../features/lorawan/system +) + +# Test & stub files +set(unittest-test-sources + features/lorawan/lorawantimer/Test_LoRaWANTimer.cpp + stubs/EventQueue_stub.cpp + stubs/mbed_assert_stub.cpp + stubs/equeue_stub.c +) + +set(unittest-test-flags + -DNDEBUG=1 + -DMBED_CONF_LORA_TX_MAX_SIZE=255 +) + diff --git a/features/lorawan/FSB_Usage.txt b/features/lorawan/FSB_Usage.txt deleted file mode 100644 index ef0706a..0000000 --- a/features/lorawan/FSB_Usage.txt +++ /dev/null @@ -1,52 +0,0 @@ -Frequency sub-bands in US915/AU915: - - US915/AU915 PHYs define channel structures that can support up to 72 channels for upstream. - The first 64 channels (0-63), occupy 125 kHz and the last 8 channels (64-71) occupy 500 kHz. - However, most of the base stations available in the market support 8 or 16 channels. - Network acquisition can become costly if the device has no prior knowledge of the active channel plan and it enables - all 72 channels to begin with. - - The LoRaWAN 1.0.2 Regional parameters specification refers to a strategy of probing a set of nine channels (8 + 1) for - the joining process. According to that strategy, the device alternatively selects a channel from a set of - 8 125 kHz channels and a 500 kHz channel. - For example, send a join request alternatively on a randomly selected channel from a set of 0-7 channels and - channel 64, which is the first 500 kHz channel. - - Once the device has joined the network (in case of OTAA) or has sent the first uplink (in the case of ABP), the network - may send a LinkAdrReq MAC command to set the channel mask to be used. Please note that these PHY layers do not - support CFList, so LinkAdrReq is the way the network tells you what channel plan to use. - - You can configure the Mbed LoRaWAN stack to use a particular frequency sub-band (FSB), which means that you don't have to - probe all sets of channels. "fsb-mask" in lorawan/mbed_lib.json is the parameter that you can use to tell the - system which FSB or set of FSBs to use. By default, the "fsb-mask" is set to "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}". - That means all channels are active. In other words, 64 125 kHz channels and 8 500 kHz channels are active. If you wish - to use a custom FSB, you need to set an appropriate mask as the value of "fsb-mask". For example, if you wish to use the - first FSB, in other words, the first 8 125 kHz channels (0-7) and the first 500 kHz channel: - "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0001}" - Similarly, if you wish to use the second FSB, in other words, the second set of 8 125 kHz channels (8-15) and the 2nd 500 kHz - channel: - "fsb-mask" = "{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}" - - You can also combine FSBs if your base station supports more than 8 channels. For example: - "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0xFF00, 0x0081}" - means use channels 0-7(125 kHz) + channel 64 (500 KHz) and channels 56-63 (125 kHz) + channel 71 (500 kHz). - - Please note that for Certification requirements, you need to alternate between 125 kHz and 500 kHz channels, so before joining, - do not set a mask that enables only 500 kHz or only 125 kHz channels. - - Frequency sub-bands in CN470 PHY: - - The LoRaPHYCN470 class defines 96 channels in total, as per the LoRaWAN Regional Specification. These 96 channels - are 125 kHz wide each and can be subdivided into 6 sub-bands containing 16 channels each. - "fsb-mask-china" is the parameter that lorawan/mbed_lib.json defines. It can be used to enforce an FSB. It is defined - as a C-style array, and the first element of the array corresponds to first 8 channels (0-7) and so on. By default, all - 96 channels are enabled, but there may be base stations that do not support all 96 channels. Therefore, network acquisition - can become cumbersome if the device hops on random channels. The probability of finding a correct channel for a base station - that supports 8 channels would be 1/12. - - For example, if your base station supports 16 channels (channels 0-15), set the "fsb-mask-china" as: - "fsb-mask-china" = "{0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}" - - Similarly, if your base station supports 8 channels (channels 0-7), set the "fsb-mask-china" as: - "fsb-mask-china" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}" - diff --git a/features/lorawan/LICENSE b/features/lorawan/LICENSE deleted file mode 100644 index d6dfb1b..0000000 --- a/features/lorawan/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ ---- Revised BSD License --- -Copyright (c) 2013, SEMTECH S.A. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Semtech corporation nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/features/lorawan/LoRaRadio.h b/features/lorawan/LoRaRadio.h deleted file mode 100644 index 601c6b9..0000000 --- a/features/lorawan/LoRaRadio.h +++ /dev/null @@ -1,667 +0,0 @@ -/** - * Copyright (c) 2017, 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. - */ - -#ifndef LORARADIO_H_ -#define LORARADIO_H_ - -/** @addtogroup LoRaWAN - * Parent class for a LoRa radio driver - * @{ - */ - -#include "platform/Callback.h" -#include "PinNames.h" - -/** - * Structure to hold RF controls for LoRa Radio. - * SX1276 have an extra control for the crystal (used in DISCO-L072CZ). - * A subset of these pins may be used by the driver in accordance with the physical - * implementation. - */ -typedef struct { - /** TX latch switch pin. - * Exact operation is implementation specific. - */ - PinName rf_switch_ctl1; - - /** RX latch switch pin. - * Exact operation is implementation specific. - */ - PinName rf_switch_ctl2; - - /** TX control pin for transceiver packaged as a module. - * Exact operation is implementation specific. - */ - PinName txctl; - - /** RX control pin for transceiver packaged as a module. - * Exact operation is implementation specific. - */ - PinName rxctl; - - /** Transceiver switch pin. - * Exact operation is implementation specific. One of the polarities of the - * pin may drive the transceiver in either TX or RX mode. - */ - PinName ant_switch; - - /** Power amplifier control pin. - * Exact operation is implementation specific. If defined, - * controls the operation of an external power amplifier. - */ - PinName pwr_amp_ctl; - - /** TCXO crystal control pin. - * Exact operation is implementation specific. - */ - PinName tcxo; -} rf_ctrls; - -/** Radio driver internal state. - * Helps identify current state of the transceiver. - */ -typedef enum radio_state { - /** IDLE state. - * Radio is in idle state. - */ - RF_IDLE = 0, - - /** RX state. - * Radio is receiving. - */ - RF_RX_RUNNING, - - /** TX state. - * Radio is transmitting. - */ - RF_TX_RUNNING, - - /** CAD state. - * Radio is detecting channel activity. - */ - RF_CAD, -} radio_state_t; - -/** Type of modem. - * [LORA/FSK] - */ -typedef enum modem_type { - /** FSK operation mode. - * Radio is using FSK modulation. - */ - MODEM_FSK = 0, - - /** LoRa operation mode. - * Radio is using LoRa modulation. - */ - MODEM_LORA -} radio_modems_t; - -/** FSK modem parameters. - * Parameters encompassing FSK modulation. - */ -typedef struct radio_fsk_settings { - /** - * Transmit power. - */ - int8_t power; - - /** - * Frequency deviation. - */ - uint32_t f_dev; - - /** - * Modulation bandwidth. - */ - uint32_t bandwidth; - - /** - * Automated frequency correction bandwidth. - */ - uint32_t bandwidth_afc; - - /** - * Data rate (SF). - */ - uint32_t datarate; - - /** - * Expected preamble length. - */ - uint16_t preamble_len; - - /** - * This flag turns on if the TX data size is fixed. - */ - bool fix_len; - - /** - * Size of outgoing data. - */ - uint8_t payload_len; - - /** - * Turn CRC on/off. - */ - bool crc_on; - - /** @deprecated - * Does not apply to FSK. Will be removed. - */ - bool iq_inverted; - - /** - * Turn continuous reception mode (such as Class C mode) on/off. - */ - bool rx_continuous; - - /** - * Timeout value in milliseconds (ms) after which the radio driver reports - * a timeout if the radio was unable to transmit. - */ - uint32_t tx_timeout; - - /** - * Timeout value in symbols (symb) after which the radio driver reports a timeout - * if the radio did not receive a Preamble. - */ - uint32_t rx_single_timeout; -} radio_fsk_settings_t; - -/** FSK packet handle. - * Contains information about an FSK packet and various metadata. - */ -typedef struct radio_fsk_packet_handler { - /** - * Set to true (1) when a Preamble is detected, otherwise false (0). - */ - uint8_t preamble_detected; - - /** - * Set to true (1) when a SyncWord is detected, otherwise false (0). - */ - uint8_t sync_word_detected; - - /** - * Storage for RSSI value of the received signal. - */ - int8_t rssi_value; - - /** - * Automated frequency correction value. - */ - int32_t afc_value; - - /** - * LNA gain value (dbm). - */ - uint8_t rx_gain; - - /** - * Size of the received data in bytes. - */ - uint16_t size; - - /** - * Keeps track of number of bytes already read from the RX FIFO. - */ - uint16_t nb_bytes; - - /** - * Stores the FIFO threshold value. - */ - uint8_t fifo_thresh; - - /** - * Defines the size of a chunk of outgoing buffer written to - * the FIFO at a unit time. For example, if the size of the data exceeds the FIFO - * limit, a certain sized chunk is written to the FIFO. Later, a FIFO-level - * interrupt enables writing of the remaining data to the FIFO chunk by chunk until - * transmission is complete. - */ - uint8_t chunk_size; -} radio_fsk_packet_handler_t; - -/** LoRa modem parameters. - * Parameters encompassing LoRa modulation. - */ -typedef struct radio_lora_settings { - /** - * Transmit power. - */ - int8_t power; - - /** - * Modulation bandwidth. - */ - uint32_t bandwidth; - - /** - * Data rate (SF). - */ - uint32_t datarate; - - /** - * Turn low data rate optimization on/off. - */ - bool low_datarate_optimize; - - /** - * Error correction code rate. - */ - uint8_t coderate; - - /** - * Preamble length in symbols. - */ - uint16_t preamble_len; - - /** - * Set to true if the outgoing payload length is fixed. - */ - bool fix_len; - - /** - * Size of outgoing payload. - */ - uint8_t payload_len; - - /** - * Turn CRC on/off. - */ - bool crc_on; - - /** - * Turn frequency hopping on/off. - */ - bool freq_hop_on; - - /** - * Number of symbols between two frequency hops. - */ - uint8_t hop_period; - - /** - * Turn IQ inversion on/off. Usually, the end device sends an IQ inverted - * signal, and the base stations do not invert. We recommended sending an - * IQ inverted signal from the device side, so any transmissions from the - * base stations do not interfere with end device transmission. - */ - bool iq_inverted; - - /** - * Turn continuous reception mode (such as in Class C) on/off. - */ - bool rx_continuous; - - /** - * Timeout in milliseconds (ms) after which the radio driver reports an error - * if the radio was unable to transmit. - */ - uint32_t tx_timeout; - - /** - * Change the network mode to Public or Private. - */ - bool public_network; -} radio_lora_settings_t; - -/** LoRa packet - * Contains information about a LoRa packet. - */ -typedef struct radio_lora_packet_handler { - /** - * Signal-to-noise ratio of a received packet. - */ - int8_t snr_value; - - /** - * RSSI value in dBm for the received packet. - */ - int8_t rssi_value; - - /** - * Size of the transmitted or received packet. - */ - uint8_t size; -} radio_lora_packet_handler_t; - -/** Global radio settings. - * Contains settings for the overall transceiver operation. - */ -typedef struct radio_settings { - /** - * Current state of the radio, such as RF_IDLE. - */ - uint8_t state; - - /** - * Current modem operation, such as MODEM_LORA. - */ - uint8_t modem; - - /** - * Current channel of operation. - */ - uint32_t channel; - - /** - * Settings for FSK modem part. - */ - radio_fsk_settings_t fsk; - - /** - * FSK packet and meta data. - */ - radio_fsk_packet_handler_t fsk_packet_handler; - - /** - * Settings for LoRa modem part. - */ - radio_lora_settings_t lora; - - /** - * LoRa packet and metadata. - */ - radio_lora_packet_handler_t lora_packet_handler; -} radio_settings_t; - -/** Reporting functions for upper layers. - * The radio driver reports various vital events to the upper controlling layers - * using callback functions provided by the upper layers at the initialization - * phase. - */ -typedef struct radio_events { - /** - * Callback when Transmission is done. - */ - mbed::Callback tx_done; - - /** - * Callback when Transmission is timed out. - */ - mbed::Callback tx_timeout; - - /** - * Rx Done callback prototype. - * - * @param payload Received buffer pointer. - * @param size Received buffer size. - * @param rssi RSSI value computed while receiving the frame [dBm]. - * @param snr Raw SNR value given by the radio hardware. - * FSK : N/A (set to 0) - * LoRa: SNR value in dB - */ - mbed::Callback rx_done; - - /** - * Callback when Reception is timed out. - */ - mbed::Callback rx_timeout; - - /** - * Callback when Reception ends up in error. - */ - mbed::Callback rx_error; - - /** - * FHSS Change Channel callback prototype. - * - * @param current_channel The index number of the current channel. - */ - mbed::Callback fhss_change_channel; - - /** - * CAD Done callback prototype. - * - * @param channel_busy True, if Channel activity detected. - */ - mbed::Callback cad_done; -} radio_events_t; - -/** - * Interface for the radios, containing the main functions that a radio needs, and five callback functions. - */ -class LoRaRadio { - -public: - - /** - * Registers radio events with the Mbed LoRaWAN stack and undergoes initialization steps, if any. - * - * @param events Contains driver callback functions. - */ - virtual void init_radio(radio_events_t *events) = 0; - - /** - * Resets the radio module. - */ - virtual void radio_reset() = 0; - - /** - * Put the RF module in sleep mode. - */ - virtual void sleep(void) = 0; - - /** - * Sets the radio to standby mode. - */ - virtual void standby(void) = 0; - - /** - * Sets reception parameters. - * - * @param modem The radio modem [0: FSK, 1: LoRa]. - * @param bandwidth Sets the bandwidth. - * FSK : >= 2600 and <= 250000 Hz - * LoRa: [0: 125 kHz, 1: 250 kHz, - * 2: 500 kHz, 3: Reserved] - * @param datarate Sets the datarate. - * FSK : 600..300000 bits/s - * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, - * 10: 1024, 11: 2048, 12: 4096 chips] - * @param coderate Sets the coding rate (LoRa only). - * FSK : N/A ( set to 0 ) - * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] - * @param bandwidth_afc Sets the AFC bandwidth (FSK only). - * FSK : >= 2600 and <= 250000 Hz - * LoRa: N/A (set to 0) - * @param preamble_len Sets the preamble length (LoRa only). - * FSK : N/A (set to 0) - * LoRa: Length in symbols (the hardware adds four more symbols). - * @param symb_timeout Sets the RxSingle timeout value. - * FSK : Timeout number of bytes - * LoRa: Timeout in symbols - * @param fix_len Fixed length packets [0: variable, 1: fixed]. - * @param payload_len Sets the payload length when fixed length is used. - * @param crc_on Enables/disables CRC [0: OFF, 1: ON]. - * @param freq_hop_on Enables/disables intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only). - * @param hop_period The number of symbols bewteen each hop (LoRa only). - * @param iq_inverted Inverts the IQ signals (LoRa only). - * FSK : N/A (set to 0) - * LoRa: [0: not inverted, 1: inverted] - * @param rx_continuous Sets the reception to continuous mode. - * [false: single mode, true: continuous mode] - */ - 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) = 0; - - /** - * Sets the transmission parameters. - * - * @param modem The radio modem [0: FSK, 1: LoRa]. - * @param power Sets the output power [dBm]. - * @param fdev Sets the frequency deviation (FSK only). - * FSK : [Hz] - * LoRa: 0 - * @param bandwidth Sets the bandwidth (LoRa only). - * FSK : 0 - * LoRa: [0: 125 kHz, 1: 250 kHz, - * 2: 500 kHz, 3: Reserved] - * @param datarate Sets the datarate. - * FSK : 600..300000 bits/s - * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, - * 10: 1024, 11: 2048, 12: 4096 chips] - * @param coderate Sets the coding rate (LoRa only). - * FSK : N/A ( set to 0 ) - * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] - * @param preamble_len Sets the preamble length. - * @param fix_len Fixed length packets [0: variable, 1: fixed]. - * @param crc_on Enables/disables CRC [0: OFF, 1: ON]. - * @param freq_hop_on Enables/disables intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only). - * @param hop_period The number of symbols between each hop (LoRa only). - * @param iq_inverted Inverts IQ signals (LoRa only) - * FSK : N/A (set to 0). - * LoRa: [0: not inverted, 1: inverted] - * @param timeout The transmission timeout [ms]. - */ - 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) = 0; - - /** - * Sends the packet. - * - * Prepares the packet to be sent and sets the radio to transmission mode. - * - * @param buffer A pointer to the buffer. - * @param size The buffer size. - */ - virtual void send(uint8_t *buffer, uint8_t size) = 0; - - /** - * Sets the radio to reception mode. - * - * To configure the receiver, use the `set_rx_config()` API. - */ - virtual void receive(void) = 0; - - /** - * Sets the carrier frequency. - * - * @param freq Channel RF frequency. - */ - virtual void set_channel(uint32_t freq) = 0; - - /** - * Generates a 32 bit random value based on RSSI readings. - * - * \remark This function sets the radio in LoRa modem mode and disables all interrupts. - * After calling this function, either `Radio.SetRxConfig` or - * `Radio.SetTxConfig` functions must be called. - * - * @return A 32 bit random value. - */ - virtual uint32_t random(void) = 0; - - /** - * Gets the radio status. - * - * @return The current radio status. - */ - virtual uint8_t get_status(void) = 0; - - /** - * Sets the maximum payload length. - * - * @param modem The radio modem [0: FSK, 1: LoRa]. - * @param max The maximum payload length in bytes. - */ - virtual void set_max_payload_length(radio_modems_t modem, uint8_t max) = 0; - - /** - * Sets the network to public or private. - * - * Updates the sync byte. Applies to LoRa modem only. - * - * @param enable If true, enables a public network. - */ - virtual void set_public_network(bool enable) = 0; - - /** - * Computes the packet time on air for the given payload. - * - * \remark This can only be called after `SetRxConfig` or `SetTxConfig`. - * - * @param modem The radio modem [0: FSK, 1: LoRa]. - * @param pkt_len The packet payload length. - * @return The computed `airTime` for the given packet payload length. - */ - virtual uint32_t time_on_air(radio_modems_t modem, uint8_t pkt_len) = 0; - - /** - * Performs carrier sensing. - * - * Checks for a certain time if the RSSI is above a given threshold. - * This threshold determines whether or not there is a transmission on - * the channel already. - * - * @param modem The type of radio modem. - * @param freq The carrier frequency. - * @param rssi_threshold The threshold value of RSSI. - * @param max_carrier_sense_time The time set for sensing the channel (ms). - * - * @return True if there is no active transmission - * in the channel, otherwise false. - */ - virtual bool perform_carrier_sense(radio_modems_t modem, - uint32_t freq, - int16_t rssi_threshold, - uint32_t max_carrier_sense_time) = 0; - - /** - * Sets the radio to CAD mode. - * - */ - virtual void start_cad(void) = 0; - - /** - * Checks whether the given RF is in range. - * - * @param frequency The frequency to check. - */ - virtual bool check_rf_frequency(uint32_t frequency) = 0; - - /** Sets the radio to continuous wave transmission mode. - * - * @param freq The RF frequency of the channel. - * @param power The output power [dBm]. - * @param time The transmission mode timeout [s]. - */ - virtual void set_tx_continuous_wave(uint32_t freq, int8_t power, uint16_t time) = 0; - - /** - * Acquires exclusive access to this radio. - */ - virtual void lock(void) = 0; - - /** - * Releases exclusive access to this radio. - */ - virtual void unlock(void) = 0; -}; - -#endif // LORARADIO_H_ -/** @}*/ diff --git a/features/lorawan/LoRaWANBase.h b/features/lorawan/LoRaWANBase.h deleted file mode 100644 index 5ab910d..0000000 --- a/features/lorawan/LoRaWANBase.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2017, 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. - */ - -#ifndef LORAWANBASE_H_ -#define LORAWANBASE_H_ - -/** - * This class is deprecated and will be removed altogether after expiration of - * deprecation notice. - */ -#include "LoRaWANInterface.h" - -MBED_DEPRECATED_SINCE("mbed-os-5.12", "Migrated to LoRaWANInterface") -typedef LoRaWANInterface LoRaWANBase; - -#endif /* LORAWANBASE_H_ */ diff --git a/features/lorawan/LoRaWANInterface.cpp b/features/lorawan/LoRaWANInterface.cpp deleted file mode 100644 index f748fbf..0000000 --- a/features/lorawan/LoRaWANInterface.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @file - * - * @brief A LoRaWAN network interface - * - * Copyright (c) 2017, 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 "LoRaWANInterface.h" -#include "lorastack/phy/loraphy_target.h" -#include "mbed-trace/mbed_trace.h" -#define TRACE_GROUP "LSTK" - -using namespace mbed; -using namespace events; - -LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio) - : _default_phy(NULL) -{ - _default_phy = new LoRaPHY_region; - MBED_ASSERT(_default_phy); - _lw_stack.bind_phy_and_radio_driver(radio, *_default_phy); -} - -LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio, LoRaPHY &phy) - : _default_phy(NULL) -{ - _lw_stack.bind_phy_and_radio_driver(radio, phy); -} - -LoRaWANInterface::~LoRaWANInterface() -{ - delete _default_phy; - _default_phy = NULL; -} - -lorawan_status_t LoRaWANInterface::initialize(EventQueue *queue) -{ - Lock lock(*this); - return _lw_stack.initialize_mac_layer(queue); -} - -lorawan_status_t LoRaWANInterface::connect() -{ - Lock lock(*this); - return _lw_stack.connect(); -} - -lorawan_status_t LoRaWANInterface::connect(const lorawan_connect_t &connect) -{ - Lock lock(*this); - return _lw_stack.connect(connect); -} - -lorawan_status_t LoRaWANInterface::disconnect() -{ - Lock lock(*this); - return _lw_stack.shutdown(); -} - -lorawan_status_t LoRaWANInterface::add_link_check_request() -{ - Lock lock(*this); - return _lw_stack.set_link_check_request(); -} - -void LoRaWANInterface::remove_link_check_request() -{ - Lock lock(*this); - _lw_stack.remove_link_check_request(); -} - -lorawan_status_t LoRaWANInterface::set_datarate(uint8_t data_rate) -{ - Lock lock(*this); - return _lw_stack.set_channel_data_rate(data_rate); -} - -lorawan_status_t LoRaWANInterface::set_confirmed_msg_retries(uint8_t count) -{ - Lock lock(*this); - return _lw_stack.set_confirmed_msg_retry(count); -} - -lorawan_status_t LoRaWANInterface::enable_adaptive_datarate() -{ - Lock lock(*this); - return _lw_stack.enable_adaptive_datarate(true); -} - -lorawan_status_t LoRaWANInterface::disable_adaptive_datarate() -{ - Lock lock(*this); - return _lw_stack.enable_adaptive_datarate(false); -} - -lorawan_status_t LoRaWANInterface::set_channel_plan(const lorawan_channelplan_t &channel_plan) -{ - Lock lock(*this); - return _lw_stack.add_channels(channel_plan); -} - -lorawan_status_t LoRaWANInterface::get_channel_plan(lorawan_channelplan_t &channel_plan) -{ - Lock lock(*this); - return _lw_stack.get_enabled_channels(channel_plan); -} - -lorawan_status_t LoRaWANInterface::remove_channel(uint8_t id) -{ - Lock lock(*this); - return _lw_stack.remove_a_channel(id); -} - -lorawan_status_t LoRaWANInterface::remove_channel_plan() -{ - Lock lock(*this); - return _lw_stack.drop_channel_list(); -} - -int16_t LoRaWANInterface::send(uint8_t port, const uint8_t *data, uint16_t length, int flags) -{ - Lock lock(*this); - return _lw_stack.handle_tx(port, data, length, flags); -} - -lorawan_status_t LoRaWANInterface::cancel_sending(void) -{ - Lock lock(*this); - return _lw_stack.stop_sending(); -} - -lorawan_status_t LoRaWANInterface::get_tx_metadata(lorawan_tx_metadata &metadata) -{ - Lock lock(*this); - return _lw_stack.acquire_tx_metadata(metadata); -} - -lorawan_status_t LoRaWANInterface::get_rx_metadata(lorawan_rx_metadata &metadata) -{ - Lock lock(*this); - return _lw_stack.acquire_rx_metadata(metadata); -} - -lorawan_status_t LoRaWANInterface::get_backoff_metadata(int &backoff) -{ - Lock lock(*this); - return _lw_stack.acquire_backoff_metadata(backoff); -} - -int16_t LoRaWANInterface::receive(uint8_t port, uint8_t *data, uint16_t length, int flags) -{ - Lock lock(*this); - return _lw_stack.handle_rx(data, length, port, flags, true); -} - -int16_t LoRaWANInterface::receive(uint8_t *data, uint16_t length, uint8_t &port, int &flags) -{ - Lock lock(*this); - return _lw_stack.handle_rx(data, length, port, flags, false); -} - -lorawan_status_t LoRaWANInterface::add_app_callbacks(lorawan_app_callbacks_t *callbacks) -{ - Lock lock(*this); - return _lw_stack.set_lora_callbacks(callbacks); -} - -lorawan_status_t LoRaWANInterface::set_device_class(const device_class_t device_class) -{ - Lock lock(*this); - return _lw_stack.set_device_class(device_class); -} diff --git a/features/lorawan/LoRaWANInterface.h b/features/lorawan/LoRaWANInterface.h deleted file mode 100644 index a55d80f..0000000 --- a/features/lorawan/LoRaWANInterface.h +++ /dev/null @@ -1,577 +0,0 @@ -/** - * Copyright (c) 2017, 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. - */ - -/** @addtogroup LoRaWAN - * Mbed OS LoRaWAN Stack - * @{ - */ - -#ifndef LORAWANINTERFACE_H_ -#define LORAWANINTERFACE_H_ - -#include "platform/Callback.h" -#include "platform/ScopedLock.h" -#include "events/EventQueue.h" -#include "LoRaWANStack.h" -#include "LoRaRadio.h" -#include "lorawan_types.h" - -// Forward declaration of LoRaPHY class -class LoRaPHY; - -/** LoRaWANInterface Class - * A network interface for LoRaWAN - */ -class LoRaWANInterface { - -public: - - /** Constructs a LoRaWANInterface using the LoRaWANStack instance underneath. - * - * Currently, LoRaWANStack is a singleton and you should only - * construct a single instance of LoRaWANInterface. - * - * LoRaWANInterface will construct PHY based on "lora.phy" setting in mbed_app.json. - * - * @param radio A reference to radio object - */ - LoRaWANInterface(LoRaRadio &radio); - - /** Constructs a LoRaWANInterface using the user provided PHY object. - - * @param radio A reference to radio object - * @param phy A reference to PHY object - */ - LoRaWANInterface(LoRaRadio &radio, LoRaPHY &phy); - - ~LoRaWANInterface(); - - /** Initialize the LoRa stack. - * - * You must call this before using the LoRa stack. - * - * @param queue A pointer to EventQueue provided by the application. - * - * @return LORAWAN_STATUS_OK on success, a negative error code on failure: - * LORAWAN_STATUS_PARAMETER_INVALID is NULL queue is given. - */ - lorawan_status_t initialize(events::EventQueue *queue); - - /** Connect OTAA or ABP using the Mbed OS config system - * - * Connect by Over The Air Activation or Activation By Personalization. - * You need to configure the connection properly using the Mbed OS configuration system. - * - * When connecting through OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) - * is negative. However, this is not a real error. It tells you that the connection is in progress, - * and an event will notify you of the completion. By default, after the Join Accept message is - * received, base stations may provide the node with a CF-List that replaces all user-configured - * channels except the Join/Default channels. A CF-List can configure a maximum of five channels - * other than the default channels. - * - * To configure more channels, we recommend that you use the `set_channel_plan()` API after the connection. - * By default, the PHY layers configure only the mandatory Join channels. The retransmission back-off - * restrictions on these channels are severe, and you may experience long delays or even failures - * in the confirmed traffic. If you add more channels, the aggregated duty cycle becomes much more - * relaxed as compared to the Join (default) channels only. - * - * **NOTES ON RECONNECTION:** - * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile memory storage. - * Therefore, the state and frame counters cannot be restored after a power cycle. However, - * if you use the `disconnect()` API to shut down the LoRaWAN protocol, the state and frame - * counters are saved. Connecting again restores the previous session. According to the LoRaWAN - * 1.0.2 specification, the frame counters are always reset to 0 for OTAA, and a new Join request - * lets the network server know that the counters need a reset. The same is said about the ABP, - * but there is no way to convey this information to the network server. For a network server, - * an ABP device is always connected. That's why storing the frame counters is important for ABP. - * That's why we restore frame counters from session information after a disconnection. - * - * @return Common: LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if connection parameters are invalid. - * - * For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call - * followed by a 'CONNECTED' event. Otherwise a negative error code is returned: - * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. - * - * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for - * the first call. Any subsequent call will return either LORAWAN_STATUS_BUSY - * (if the previous request for connection is still underway) or - * LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). - * A 'CONNECTED' event is sent to the application when the JoinAccept is received. - */ - lorawan_status_t connect(); - - /** Connect OTAA or ABP with parameters - * - * All connection parameters are chosen by you and provided in the data structure passed down. - * - * When connecting using OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) - * is negative. However, this is not a real error. It tells you that connection is in progress, - * and an event will notify you of completion. By default, after Join Accept message is received, - * base stations may provide the node with a CF-List that replaces all user-configured channels - * except the Join/Default channels. A CF-List can configure a maximum of five channels other - * than the default channels. - * - * To configure more channels, we recommend that you use the `set_channel_plan()` API after - * the connection. By default, the PHY layers configure only the mandatory Join channels. - * The retransmission back-off restrictions on these channels are severe, and you may experience - * long delays or even failures in the confirmed traffic. If you add more channels, the aggregated - * duty cycle becomes much more relaxed as compared to the Join (default) channels only. - * - * **NOTES ON RECONNECTION:** - * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile memory storage. - * Therefore, the state and frame counters cannot be restored after a power cycle. However, - * if you use the `disconnect()` API to shut down the LoRaWAN protocol, the state and frame - * counters are saved. Connecting again restores the previous session. According to the LoRaWAN - * 1.0.2 specification, the frame counters are always reset to zero for OTAA, and a new Join - * request lets the network server know that the counters need a reset. The same is said about - * the ABP, but there is no way to convey this information to the network server. For a network - * server, an ABP device is always connected. That's why storing the frame counters is important - * for ABP. That's why we restore frame counters from session information after a disconnection. - * - * @param connect Options for an end device connection to the gateway. - * - * @return Common: LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if connection parameters are invalid. - * - * For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed - * by a 'CONNECTED' event. Otherwise a negative error code is returned. - * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. - * - * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the - * first call. Any subsequent call will return either LORAWAN_STATUS_BUSY - * (if the previous request for connection is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED - * (if a network was already joined successfully). - * A 'CONNECTED' event is sent to the application when the JoinAccept is received. - */ - lorawan_status_t connect(const lorawan_connect_t &connect); - - /** Disconnect the current session. - * - * @return LORAWAN_STATUS_DEVICE_OFF on success, a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - */ - lorawan_status_t disconnect(); - - /** Validate the connectivity with the network. - * - * Application may use this API to submit a request to the stack for validation of its connectivity - * to a Network Server. Under the hood, this API schedules a Link Check Request command (LinkCheckReq) - * for the network server and once the response, i.e., LinkCheckAns MAC command is received from - * the Network Server, user provided method is called. - * - * One way to use this API may be the validation of connectivity after a long deep sleep. - * Mbed LoRaWANStack follows the MAC commands with data frame payload, so the application needs - * to send something, and the Network Server may respond during the RX slots. - * - * This API is usable only when the application sets the 'link_check_resp' callback. - * See add_lora_app_callbacks API. If the above mentioned callback is not set, - * a LORAWAN_STATUS_PARAMETER_INVALID error is thrown. - * - * The first parameter to callback function is the demodulation margin, and the second parameter - * is the number of gateways that successfully received the last request. - * - * A 'Link Check Request' MAC command remains set for every subsequent transmission, until/unless - * the application explicitly turns it off using the remove_link_check_request() API. - * - * @return LORAWAN_STATUS_OK on successfully queuing a request, or - * a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if link_check_resp callback method is not set. - * - */ - lorawan_status_t add_link_check_request(); - - /** Removes link check request sticky MAC command. - * - * Any already queued request may still be completed. However, no new requests will be made. - */ - void remove_link_check_request(); - - /** Sets up a particular data rate - * - * @param data_rate The intended data rate, for example DR_0 or DR_1. - * Please note that the macro DR_* can mean different things in different regions. - * @return LORAWAN_STATUS_OK if everything goes well, otherwise a negative error code: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if ADR is enabled or invalid data rate is given - */ - lorawan_status_t set_datarate(uint8_t data_rate); - - /** Enables adaptive data rate (ADR) - * - * The underlying LoRaPHY and LoRaMac layers handle the data rate automatically - * based on the radio conditions (network congestion). - * - * @return LORAWAN_STATUS_OK on success, negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() - */ - lorawan_status_t enable_adaptive_datarate(); - - /** Disables adaptive data rate - * - * When adaptive data rate (ADR) is disabled, either you can set a certain - * data rate, or the MAC layer selects a default value. - * - * @return LORAWAN_STATUS_OK on success, negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() - */ - lorawan_status_t disable_adaptive_datarate(); - - /** Sets up the retry counter for confirmed messages. - * - * Valid for confirmed messages only. - * - * The number of trials to transmit the frame, if the LoRaMAC layer did not receive an - * acknowledgment. The MAC performs a data rate adaptation as in the LoRaWAN Specification - * V1.0.2, chapter 18.4, table on page 64. - * - * Note that if the number of retries is set to 1 or 2, MAC does not decrease the data rate, - * if the LoRaMAC layer did not receive an acknowledgment. - * - * @param count The number of retries for confirmed messages. - * - * @return LORAWAN_STATUS_OK or a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize() - * LORAWAN_STATUS_PARAMETER_INVALID if count >= 255 - */ - lorawan_status_t set_confirmed_msg_retries(uint8_t count); - - /** Sets the channel plan. - * - * You can provide a list of channels with appropriate parameters filled in. However, - * this list is not absolute. The stack applies a CF-List whenever available, which means - * that the network can overwrite your channel frequency settings right after Join Accept - * is received. You may try to set up any channel or channels after that, and if the channel - * requested is already active, the request is silently ignored. A negative error code is - * returned if there is any problem with parameters. - * - * Please note that you can also use this API to add a single channel to the existing channel plan. - * - * There is no reverse mechanism in the 1.0.2 specification for a node to request a particular - * channel. Only the network server can initiate such a request. - * You need to ensure that the corresponding base station supports the channel or channels being added. - * - * If your list includes a default channel (a channel where Join Requests are received), - * you cannot fully configure the channel parameters. Either leave the channel settings to default, - * or check your corresponding PHY layer implementation. For example, LoRaPHYE868. - * - * @param channel_plan The channel plan to set. - * - * @return LORAWAN_STATUS_OK on success, a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if number of channels is exceeding the PHY limit, - * LORAWAN_STATUS_DATARATE_INVALID if invalid data rate is given, - * LORAWAN_STATUS_FREQUENCY_INVALID if invalid frequency is given, - * LORAWAN_STATUS_FREQ_AND_DR_INVALID if invalid data rate and freqency are given, - * LORAWAN_STATUS_BUSY if TX currently ongoing, - * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY - */ - lorawan_status_t set_channel_plan(const lorawan_channelplan_t &channel_plan); - - /** Gets the channel plans from the LoRa stack. - * - * Once you have selected a particular PHY layer, a set of channels is automatically activated. - * Right after connecting, you can use this API to see the current plan. Otherwise, this API - * returns the channel plan that you have set using `set_channel_plan()`. - * - * @param channel_plan The current channel plan information. - * - * @return LORAWAN_STATUS_OK on success, a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY - */ - lorawan_status_t get_channel_plan(lorawan_channelplan_t &channel_plan); - - /** Removes an active channel plan. - * - * You cannot remove default channels (the channels the base stations are listening to). - * When a plan is abolished, only the non-default channels are removed. - * - * @return LORAWAN_STATUS_OK on success, negative error code on failure - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_BUSY if TX currently ongoing, - * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY - */ - lorawan_status_t remove_channel_plan(); - - /** Removes a single channel. - * - * You cannot remove default channels (the channels the base stations are listening to). - * - * @param index The channel index. - * - * @return LORAWAN_STATUS_OK on success, negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if invalid channel index is given, - * LORAWAN_STATUS_BUSY if TX currently ongoing, - * LORAWAN_STATUS_SERVICE_UNKNOWN if custom channel plans are disabled in PHY - */ - lorawan_status_t remove_channel(uint8_t index); - - /** Send message to gateway - * - * @param port The application port number. Port numbers 0 and 224 are reserved, - * whereas port numbers from 1 to 223 (0x01 to 0xDF) are valid port numbers. - * Anything out of this range is illegal. - * - * @param data A pointer to the data being sent. The ownership of the buffer is not transferred. - * The data is copied to the internal buffers. - * - * @param length The size of data in bytes. - * - * @param flags A flag used to determine what type of message is being sent, for example: - * - * MSG_UNCONFIRMED_FLAG = 0x01 - * MSG_CONFIRMED_FLAG = 0x02 - * MSG_MULTICAST_FLAG = 0x04 - * MSG_PROPRIETARY_FLAG = 0x08 - * - * All flags are mutually exclusive, and MSG_MULTICAST_FLAG cannot be set. - * - * @return The number of bytes sent, or a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, - * LORAWAN_STATUS_WOULD_BLOCK if another TX is ongoing, - * LORAWAN_STATUS_PORT_INVALID if trying to send to an invalid port (e.g. to 0) - * LORAWAN_STATUS_PARAMETER_INVALID if NULL data pointer is given or flags are invalid. - */ - int16_t send(uint8_t port, const uint8_t *data, uint16_t length, int flags); - - /** Receives a message from the Network Server on a specific port. - * - * @param port The application port number. Port numbers 0 and 224 are reserved, - * whereas port numbers from 1 to 223 (0x01 to 0xDF) are valid port numbers. - * Anything out of this range is illegal. - * - * @param data A pointer to buffer where the received data will be stored. - * - * @param length The size of data in bytes. - * - * @param flags A flag is used to determine what type of message is being sent, for example: - * - * MSG_UNCONFIRMED_FLAG = 0x01 - * MSG_CONFIRMED_FLAG = 0x02 - * MSG_MULTICAST_FLAG = 0x04 - * MSG_PROPRIETARY_FLAG = 0x08 - * - * All flags can be used in conjunction with one another depending on the intended - * use case or reception expectation. - * - * For example, MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are - * not mutually exclusive. In other words, the user can subscribe to - * receive both CONFIRMED AND UNCONFIRMED messages at the same time. - * - * @return It could be one of these: - * i) 0 if there is nothing else to read. - * ii) Number of bytes written to user buffer. - * iii) A negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, - * LORAWAN_STATUS_WOULD_BLOCK if there is nothing available to read at the moment, - * LORAWAN_STATUS_PARAMETER_INVALID if NULL data or length is given, - * LORAWAN_STATUS_WOULD_BLOCK if incorrect port or flags are given, - */ - int16_t receive(uint8_t port, uint8_t *data, uint16_t length, int flags); - - /** Receives a message from the Network Server on any port. - * - * @param data A pointer to buffer where the received data will be stored. - * - * @param length The size of data in bytes - * - * @param port Return the number of port from which message was received. - * - * @param flags Return flags to determine what type of message was received. - * MSG_UNCONFIRMED_FLAG = 0x01 - * MSG_CONFIRMED_FLAG = 0x02 - * MSG_MULTICAST_FLAG = 0x04 - * MSG_PROPRIETARY_FLAG = 0x08 - * - * @return It could be one of these: - * i) 0 if there is nothing else to read. - * ii) Number of bytes written to user buffer. - * iii) A negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_NO_ACTIVE_SESSIONS if connection is not open, - * LORAWAN_STATUS_PARAMETER_INVALID if NULL data or length is given, - * LORAWAN_STATUS_WOULD_BLOCK if there is nothing available to read at the moment. - */ - int16_t receive(uint8_t *data, uint16_t length, uint8_t &port, int &flags); - - /** Add application callbacks to the stack. - * - * An example of using this API with a latch onto 'lorawan_events' could be: - * - *\code - * LoRaWANInterface lorawan(radio); - * lorawan_app_callbacks_t cbs; - * static void my_event_handler(); - * - * int main() - * { - * lorawan.initialize(); - * cbs.lorawan_events = mbed::callback(my_event_handler); - * lorawan.add_app_callbacks(&cbs); - * lorawan.connect(); - * } - * - * static void my_event_handler(lorawan_event_t event) - * { - * switch(event) { - * case CONNECTED: - * //do something - * break; - * case DISCONNECTED: - * //do something - * break; - * case TX_DONE: - * //do something - * break; - * default: - * break; - * } - * } - * - *\endcode - * - * @param callbacks A pointer to the structure containing application callbacks. - * - * @return LORAWAN_STATUS_OK on success, a negative error code on failure: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_PARAMETER_INVALID if events callback is not set - */ - lorawan_status_t add_app_callbacks(lorawan_app_callbacks_t *callbacks); - - /** Change device class - * - * Change current device class. - * - * @param device_class The device class - * - * @return LORAWAN_STATUS_OK on success or other negative error code if request failed: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_UNSUPPORTED if requested class is not supported - */ - lorawan_status_t set_device_class(device_class_t device_class); - - /** Get hold of TX meta-data - * - * Use this method to acquire any TX meta-data related to previous transmission. - * TX meta-data is only available right after the transmission is completed. - * In other words, you can check for TX meta-data right after receiving the TX_DONE event. - * - * @param metadata the inbound structure that will be filled if the meta-data is available. - * - * @return LORAWAN_STATUS_OK if the meta-data is available, - * otherwise other negative error code if request failed: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available - */ - lorawan_status_t get_tx_metadata(lorawan_tx_metadata &metadata); - - /** Get hold of RX meta-data - * - * Use this method to acquire any RX meta-data related to current reception. - * RX meta-data is only available right after the reception is completed. - * In other words, you can check for RX meta-data right after receiving the RX_DONE event. - * - * @param metadata the inbound structure that will be filled if the meta-data is available. - * - * @return LORAWAN_STATUS_OK if the meta-data is available, - * otherwise other negative error code if request failed: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available - */ - lorawan_status_t get_rx_metadata(lorawan_rx_metadata &metadata); - - /** Get hold of backoff time - * - * In the TX path, because of automatic duty cycling, the transmission is delayed by a certain - * amount of time, which is the backoff time. While the system schedules application data to be sent, - * the application can inquire about how much time is left in the actual transmission to happen. - * - * The system will provide you with a backoff time only if the application data is in the TX pipe. - * If however, the event is already queued for the transmission, this API returns a - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE error code. - * - * @param backoff the inbound integer that will carry the backoff time if it is available. - * - * @return LORAWAN_STATUS_OK if the meta-data is available, - * otherwise other negative error code if request failed: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE if the meta-data is not available - */ - lorawan_status_t get_backoff_metadata(int &backoff); - - /** Cancel outgoing transmission - * - * This API is used to cancel any outstanding transmission in the TX pipe. - * If an event for transmission is not already queued at the end of backoff timer, - * the system can cancel the outstanding outgoing packet. Otherwise, the system is - * busy sending and can't be held back. The system will not try to resend if the - * outgoing message was a CONFIRMED message even if the ack is not received. - * - * @return LORAWAN_STATUS_OK if the sending is canceled, otherwise - * other negative error code if request failed: - * LORAWAN_STATUS_NOT_INITIALIZED if system is not initialized with initialize(), - * LORAWAN_STATUS_BUSY if the send cannot be canceled - * LORAWAN_STATUS_NO_OP if the operation cannot be completed (nothing to cancel) - */ - lorawan_status_t cancel_sending(void); - - /** Provides exclusive access to the stack. - * - * Use only if the stack is being run in it's own separate thread. - */ - void lock(void) - { - _lw_stack.lock(); - } - - /** Releases exclusive access to the stack. - * - * Use only if the stack is being run in it's own separate thread. - */ - void unlock(void) - { - _lw_stack.unlock(); - } - -private: - /** ScopedLock object - * - * RAII style exclusive access - */ - typedef mbed::ScopedLock Lock; - - /** LoRaWANStack object - * - * Handle for the LoRaWANStack class - */ - LoRaWANStack _lw_stack; - - /** PHY object if created by LoRaWANInterface - * - * PHY object if LoRaWANInterface has created it. - * If PHY object is provided by the application, this pointer is NULL. - */ - LoRaPHY *_default_phy; -}; - -#endif /* LORAWANINTERFACE_H_ */ -/** @}*/ diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp deleted file mode 100644 index d60fa0b..0000000 --- a/features/lorawan/LoRaWANStack.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRaWAN stack layer that controls both MAC and PHY underneath - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#include -#include -#include "platform/Callback.h" -#include "events/EventQueue.h" - -#include "LoRaWANStack.h" - -#include "mbed-trace/mbed_trace.h" -#define TRACE_GROUP "LSTK" - -#define INVALID_PORT 0xFF -#define MAX_CONFIRMED_MSG_RETRIES 255 -#define COMPLIANCE_TESTING_PORT 224 -/** - * Control flags for transient states - */ -#define IDLE_FLAG 0x00000000 -#define RETRY_EXHAUSTED_FLAG 0x00000001 -#define MSG_RECVD_FLAG 0x00000002 -#define CONNECTED_FLAG 0x00000004 -#define USING_OTAA_FLAG 0x00000008 -#define TX_DONE_FLAG 0x00000010 -#define CONN_IN_PROGRESS_FLAG 0x00000020 - -using namespace mbed; -using namespace events; - -/** - * Bit mask for message flags - */ - -#define MSG_FLAG_MASK 0x0F - -/***************************************************************************** - * Constructor * - ****************************************************************************/ -LoRaWANStack::LoRaWANStack() - : _loramac(), - _device_current_state(DEVICE_STATE_NOT_INITIALIZED), - _lw_session(), - _tx_msg(), - _rx_msg(), - _tx_metadata(), - _rx_metadata(), - _num_retry(1), - _qos_cnt(1), - _ctrl_flags(IDLE_FLAG), - _app_port(INVALID_PORT), - _link_check_requested(false), - _automatic_uplink_ongoing(false), - _queue(NULL) -{ - _tx_metadata.stale = true; - _rx_metadata.stale = true; - core_util_atomic_flag_clear(&_rx_payload_in_use); - -#ifdef MBED_CONF_LORA_APP_PORT - if (is_port_valid(MBED_CONF_LORA_APP_PORT)) { - _app_port = MBED_CONF_LORA_APP_PORT; - } else { - tr_error("User defined port in .json is illegal."); - } -#endif -} - -/***************************************************************************** - * Public Methods * - ****************************************************************************/ -void LoRaWANStack::bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy) -{ - radio_events.tx_done = mbed::callback(this, &LoRaWANStack::tx_interrupt_handler); - radio_events.rx_done = mbed::callback(this, &LoRaWANStack::rx_interrupt_handler); - radio_events.rx_error = mbed::callback(this, &LoRaWANStack::rx_error_interrupt_handler); - radio_events.tx_timeout = mbed::callback(this, &LoRaWANStack::tx_timeout_interrupt_handler); - radio_events.rx_timeout = mbed::callback(this, &LoRaWANStack::rx_timeout_interrupt_handler); - - phy.set_radio_instance(radio); - _loramac.bind_phy(phy); - - radio.lock(); - radio.init_radio(&radio_events); - radio.unlock(); -} - -lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) -{ - if (!queue) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - tr_debug("Initializing MAC layer"); - _queue = queue; - - return state_controller(DEVICE_STATE_IDLE); -} - -lorawan_status_t LoRaWANStack::set_lora_callbacks(const lorawan_app_callbacks_t *callbacks) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!callbacks || !callbacks->events) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - _callbacks.events = callbacks->events; - - if (callbacks->link_check_resp) { - _callbacks.link_check_resp = callbacks->link_check_resp; - } - - if (callbacks->battery_level) { - _callbacks.battery_level = callbacks->battery_level; - _loramac.set_batterylevel_callback(callbacks->battery_level); - } - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaWANStack::connect() -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { - return LORAWAN_STATUS_BUSY; - } - - if (_ctrl_flags & CONNECTED_FLAG) { - return LORAWAN_STATUS_ALREADY_CONNECTED; - } - - lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); - - if (LORAWAN_STATUS_OK != status) { - return status; - } - - return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); -} - -lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { - return LORAWAN_STATUS_BUSY; - } - - if (_ctrl_flags & CONNECTED_FLAG) { - return LORAWAN_STATUS_ALREADY_CONNECTED; - } - - if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA) - && !(connect.connect_type == LORAWAN_CONNECTION_ABP)) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA); - - lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa); - - if (LORAWAN_STATUS_OK != status) { - return status; - } - - return handle_connect(is_otaa); -} - -lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return _loramac.add_channel_plan(channel_plan); -} - -lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return _loramac.remove_single_channel(channel_id); -} - -lorawan_status_t LoRaWANStack::drop_channel_list() -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return _loramac.remove_channel_plan(); -} - -lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t &channel_plan) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return _loramac.get_channel_plan(channel_plan); -} - -lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (count >= MAX_CONFIRMED_MSG_RETRIES) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - _num_retry = count; - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return _loramac.set_channel_data_rate(data_rate); -} - - -lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - _loramac.enable_adaptive_datarate(adr_enabled); - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaWANStack::stop_sending(void) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - lorawan_status_t status = _loramac.clear_tx_pipe(); - - if (status == LORAWAN_STATUS_OK) { - _ctrl_flags &= ~TX_DONE_FLAG; - _loramac.set_tx_ongoing(false); - _device_current_state = DEVICE_STATE_IDLE; - return LORAWAN_STATUS_OK; - } - - return status; -} - -int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data, - uint16_t length, uint8_t flags, - bool null_allowed, bool allow_port_0) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!null_allowed && !data) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - if (!_lw_session.active) { - return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; - } - - if (_loramac.tx_ongoing()) { - return LORAWAN_STATUS_WOULD_BLOCK; - } - - // add a link check request with normal data, until the application - // explicitly removes it. - if (_link_check_requested) { - _loramac.setup_link_check_request(); - } - _qos_cnt = 1; - - lorawan_status_t status; - - if (_loramac.nwk_joined() == false) { - return LORAWAN_STATUS_NO_NETWORK_JOINED; - } - - status = set_application_port(port, allow_port_0); - - if (status != LORAWAN_STATUS_OK) { - tr_error("Illegal application port definition."); - return status; - } - - // All the flags are mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be - // used for uplink. - switch (flags & MSG_FLAG_MASK) { - case MSG_UNCONFIRMED_FLAG: - case MSG_CONFIRMED_FLAG: - case MSG_PROPRIETARY_FLAG: - break; - - default: - tr_error("Invalid send flags"); - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry); - - status = state_controller(DEVICE_STATE_SCHEDULING); - - // send user the length of data which is scheduled now. - // user should take care of the pending data. - return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status; -} - -int16_t LoRaWANStack::handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!_lw_session.active) { - return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; - } - - // No messages to read. - if (!_rx_msg.receive_ready) { - return LORAWAN_STATUS_WOULD_BLOCK; - } - - if (data == NULL || length == 0) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type); - if (validate_params) { - // Check received message port and flags match with the ones requested by user - received_flags &= MSG_FLAG_MASK; - - if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) { - return LORAWAN_STATUS_WOULD_BLOCK; - } - } - - // Report values back to user - port = _rx_msg.msg.mcps_indication.port; - flags = received_flags; - - const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer; - uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size; - bool read_complete = false; - - if (_rx_msg.pending_size == 0) { - _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size; - _rx_msg.prev_read_size = 0; - } - - // check the length of received message whether we can fit into user - // buffer completely or not - if (_rx_msg.prev_read_size == 0 && _rx_msg.msg.mcps_indication.buffer_size <= length) { - memcpy(data, base_ptr, base_size); - read_complete = true; - } else if (_rx_msg.pending_size > length) { - _rx_msg.pending_size = _rx_msg.pending_size - length; - base_size = length; - memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); - _rx_msg.prev_read_size += base_size; - } else { - base_size = _rx_msg.pending_size; - memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); - read_complete = true; - } - - if (read_complete) { - _rx_msg.msg.mcps_indication.buffer = NULL; - _rx_msg.msg.mcps_indication.buffer_size = 0; - _rx_msg.pending_size = 0; - _rx_msg.receive_ready = false; - } - - return base_size; -} - -lorawan_status_t LoRaWANStack::set_link_check_request() -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!_callbacks.link_check_resp) { - tr_error("Must assign a callback function for link check request. "); - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - _link_check_requested = true; - return LORAWAN_STATUS_OK; -} - -void LoRaWANStack::remove_link_check_request() -{ - _link_check_requested = false; -} - -lorawan_status_t LoRaWANStack::shutdown() -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - return state_controller(DEVICE_STATE_SHUTDOWN); -} - -lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_class) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (device_class == CLASS_B) { - return LORAWAN_STATUS_UNSUPPORTED; - } - _loramac.set_device_class(device_class, - mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception)); - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaWANStack::acquire_tx_metadata(lorawan_tx_metadata &tx_metadata) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!_tx_metadata.stale) { - tx_metadata = _tx_metadata; - _tx_metadata.stale = true; - return LORAWAN_STATUS_OK; - } - - return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; -} - -lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - if (!_rx_metadata.stale) { - metadata = _rx_metadata; - _rx_metadata.stale = true; - return LORAWAN_STATUS_OK; - } - - return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; -} - -lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - int id = _loramac.get_backoff_timer_event_id(); - - if (_loramac.get_backoff_timer_event_id() > 0) { - backoff = _queue->time_left(id); - return LORAWAN_STATUS_OK; - } - - backoff = -1; - return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; -} - -/***************************************************************************** - * Interrupt handlers * - ****************************************************************************/ -void LoRaWANStack::tx_interrupt_handler(void) -{ - _tx_timestamp = _loramac.get_current_time(); - const int ret = _queue->call(this, &LoRaWANStack::process_transmission); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaWANStack::rx_interrupt_handler(const uint8_t *payload, uint16_t size, - int16_t rssi, int8_t snr) -{ - if (size > sizeof _rx_payload || core_util_atomic_flag_test_and_set(&_rx_payload_in_use)) { - return; - } - - memcpy(_rx_payload, payload, size); - - const uint8_t *ptr = _rx_payload; - const int ret = _queue->call(this, &LoRaWANStack::process_reception, - ptr, size, rssi, snr); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaWANStack::rx_error_interrupt_handler(void) -{ - const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, - false); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaWANStack::tx_timeout_interrupt_handler(void) -{ - const int ret = _queue->call(this, &LoRaWANStack::process_transmission_timeout); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaWANStack::rx_timeout_interrupt_handler(void) -{ - const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, - true); - MBED_ASSERT(ret != 0); - (void)ret; -} - -/***************************************************************************** - * Processors for deferred interrupts * - ****************************************************************************/ -void LoRaWANStack::process_transmission_timeout() -{ - // this is a fatal error and should not happen - tr_debug("TX Timeout"); - _loramac.on_radio_tx_timeout(); - _ctrl_flags &= ~TX_DONE_FLAG; - if (_device_current_state == DEVICE_STATE_JOINING) { - mlme_confirm_handler(); - } else { - state_controller(DEVICE_STATE_STATUS_CHECK); - } - - state_machine_run_to_completion(); -} - -void LoRaWANStack::process_transmission(void) -{ - tr_debug("Transmission completed"); - - if (_device_current_state == DEVICE_STATE_JOINING) { - _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; - } - - if (_device_current_state == DEVICE_STATE_SENDING) { - if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { - tr_debug("Awaiting ACK"); - _device_current_state = DEVICE_STATE_AWAITING_ACK; - } - } - - _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 &= ~RETRY_EXHAUSTED_FLAG; - tr_debug("Ack=OK, NbTrials=%d", - _loramac.get_mcps_confirmation()->nb_retries); - _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; - _loramac.post_process_mcps_req(); - make_tx_metadata_available(); - 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); - } - } -} - -void LoRaWANStack::post_process_tx_no_reception() -{ - if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { - if (_loramac.continue_sending_process()) { - _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_machine_run_to_completion(); -} - -void LoRaWANStack::handle_scheduling_failure(void) -{ - tr_error("Failed to schedule transmission"); - state_controller(DEVICE_STATE_STATUS_CHECK); - state_machine_run_to_completion(); -} - - -void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size, - int16_t rssi, int8_t snr) -{ - _device_current_state = DEVICE_STATE_RECEIVING; - - _ctrl_flags &= ~MSG_RECVD_FLAG; - _ctrl_flags &= ~TX_DONE_FLAG; - _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; - - _loramac.on_radio_rx_done(payload, size, rssi, snr); - - if (_loramac.get_mlme_confirmation()->pending) { - _loramac.post_process_mlme_request(); - mlme_confirm_handler(); - - if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { - core_util_atomic_flag_clear(&_rx_payload_in_use); - return; - } - } - - if (!_loramac.nwk_joined()) { - core_util_atomic_flag_clear(&_rx_payload_in_use); - return; - } - - make_rx_metadata_available(); - - // Post process transmission in response to the reception - post_process_tx_with_reception(); - - // handle any pending MCPS indication - if (_loramac.get_mcps_indication()->pending) { - _loramac.post_process_mcps_ind(); - _ctrl_flags |= MSG_RECVD_FLAG; - state_controller(DEVICE_STATE_STATUS_CHECK); - } - - // complete the cycle only if TX_DONE_FLAG is set - if (_ctrl_flags & TX_DONE_FLAG) { - state_machine_run_to_completion(); - } - - // 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"); - _loramac.post_process_mlme_ind(); - tr_debug("Immediate Uplink requested"); - mlme_indication_handler(); - } - - core_util_atomic_flag_clear(&_rx_payload_in_use); -} - -void LoRaWANStack::process_reception_timeout(bool is_timeout) -{ - rx_slot_t slot = _loramac.get_current_slot(); - - // when is_timeout == false, a CRC error took place in the received frame - // we treat that erroneous frame as no frame received at all, hence handle - // it exactly as we would handle timeout - _loramac.on_radio_rx_timeout(is_timeout); - - if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) { - state_controller(DEVICE_STATE_JOINING); - return; - } - - /** - * LoRaWAN Specification 1.0.2. Section 3.3.6 - * Main point: - * We indicate successful transmission - * of UNCONFIRMED message after RX windows are done with. - * For a CONFIRMED message, it means that we have not received - * ack (actually nothing was received), and we should retransmit if we can. - * - * NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout - * never occurs. - */ - if (slot == RX_SLOT_WIN_2) { - post_process_tx_no_reception(); - } -} - -/***************************************************************************** - * Private methods * - ****************************************************************************/ -void LoRaWANStack::make_tx_metadata_available(void) -{ - _tx_metadata.stale = false; - _tx_metadata.channel = _loramac.get_mcps_confirmation()->channel; - _tx_metadata.data_rate = _loramac.get_mcps_confirmation()->data_rate; - _tx_metadata.tx_power = _loramac.get_mcps_confirmation()->tx_power; - _tx_metadata.tx_toa = _loramac.get_mcps_confirmation()->tx_toa; - _tx_metadata.nb_retries = _loramac.get_mcps_confirmation()->nb_retries; -} - -void LoRaWANStack::make_rx_metadata_available(void) -{ - _rx_metadata.stale = false; - _rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate; - _rx_metadata.rssi = _loramac.get_mcps_indication()->rssi; - _rx_metadata.snr = _loramac.get_mcps_indication()->snr; - _rx_metadata.channel = _loramac.get_mcps_indication()->channel; - _rx_metadata.rx_toa = _loramac.get_mcps_indication()->rx_toa; -} - -bool LoRaWANStack::is_port_valid(const uint8_t port, bool allow_port_0) -{ - //Application should not use reserved and illegal port numbers. - if (port == 0) { - return allow_port_0; - } else if (port == COMPLIANCE_TESTING_PORT) { -#if !defined(LORAWAN_COMPLIANCE_TEST) - return false; -#endif - } else { - return true; - } - - // fallback for compliance testing port if LORAWAN_COMPLIANCE_TEST - // was defined - return true; -} - -lorawan_status_t LoRaWANStack::set_application_port(const uint8_t port, bool allow_port_0) -{ - if (is_port_valid(port, allow_port_0)) { - _app_port = port; - return LORAWAN_STATUS_OK; - } - - return LORAWAN_STATUS_PORT_INVALID; -} - -void LoRaWANStack::state_machine_run_to_completion() -{ - if (_loramac.get_device_class() == CLASS_C) { - _device_current_state = DEVICE_STATE_RECEIVING; - return; - } - - _device_current_state = DEVICE_STATE_IDLE; -} - -void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const -{ - if (_callbacks.events) { - const int ret = _queue->call(_callbacks.events, event); - MBED_ASSERT(ret != 0); - (void)ret; - } -} - -void LoRaWANStack::send_automatic_uplink_message(const uint8_t port) -{ - // we will silently ignore the automatic uplink event if the user is already - // sending something - const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true); - if (ret == LORAWAN_STATUS_WOULD_BLOCK) { - _automatic_uplink_ongoing = false; - } else if (ret < 0) { - tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret); - send_event_to_application(AUTOMATIC_UPLINK_ERROR); - } -} - -int LoRaWANStack::convert_to_msg_flag(const mcps_type_t type) -{ - int msg_flag = MSG_UNCONFIRMED_FLAG; - switch (type) { - case MCPS_UNCONFIRMED: - msg_flag = MSG_UNCONFIRMED_FLAG; - break; - - case MCPS_CONFIRMED: - msg_flag = MSG_CONFIRMED_FLAG; - break; - - case MCPS_MULTICAST: - msg_flag = MSG_MULTICAST_FLAG; - break; - - case MCPS_PROPRIETARY: - msg_flag = MSG_PROPRIETARY_FLAG; - break; - - default: - tr_error("Unknown message type!"); - MBED_ASSERT(0); - } - - return msg_flag; -} - -lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa) -{ - _ctrl_flags |= CONN_IN_PROGRESS_FLAG; - - if (is_otaa) { - tr_debug("Initiating OTAA"); - - // In 1.0.2 spec, counters are always set to zero for new connection. - // This section is common for both normal and - // connection restore at this moment. Will change in future with 1.1 support. - _lw_session.downlink_counter = 0; - _lw_session.uplink_counter = 0; - _ctrl_flags |= USING_OTAA_FLAG; - } else { - // If current state is SHUTDOWN, device may be trying to re-establish - // communication. In case of ABP specification is meddled about frame counters. - // It says to reset counters to zero but there is no mechanism to tell the - // network server that the device was disconnected or restarted. - // At the moment, this implementation does not support a non-volatile - // memory storage. - //_lw_session.downlink_counter; //Get from NVM - //_lw_session.uplink_counter; //Get from NVM - - tr_debug("Initiating ABP"); - tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", - _lw_session.uplink_counter, _lw_session.downlink_counter); - _ctrl_flags &= ~USING_OTAA_FLAG; - } - - return state_controller(DEVICE_STATE_CONNECTING); -} - -void LoRaWANStack::mlme_indication_handler() -{ - if (_loramac.get_mlme_indication()->indication_type == MLME_SCHEDULE_UPLINK) { - // The MAC signals that we shall provide an uplink as soon as possible -#if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE - _automatic_uplink_ongoing = true; - tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands..."); - const uint8_t port = 0; - const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port); - MBED_ASSERT(ret != 0); - (void)ret; -#else - send_event_to_application(UPLINK_REQUIRED); -#endif - return; - } - - tr_error("Unknown MLME Indication type."); -} - -void LoRaWANStack::mlme_confirm_handler() -{ - if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK) { - if (_loramac.get_mlme_confirmation()->status - == LORAMAC_EVENT_INFO_STATUS_OK) { - - if (_callbacks.link_check_resp) { - const int ret = _queue->call( - _callbacks.link_check_resp, - _loramac.get_mlme_confirmation()->demod_margin, - _loramac.get_mlme_confirmation()->nb_gateways); - MBED_ASSERT(ret != 0); - (void) ret; - } - } - } - - if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { - - switch (_loramac.get_mlme_confirmation()->status) { - case LORAMAC_EVENT_INFO_STATUS_OK: - state_controller(DEVICE_STATE_CONNECTED); - break; - - case LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL: - // fatal error - _device_current_state = DEVICE_STATE_IDLE; - tr_error("Joining abandoned: CRYPTO_ERROR"); - send_event_to_application(CRYPTO_ERROR); - break; - - case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: - // fatal error - _device_current_state = DEVICE_STATE_IDLE; - tr_error("Joining abandoned: Radio failed to transmit"); - send_event_to_application(TX_TIMEOUT); - break; - - default: - // non-fatal, retry if possible - _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; - state_controller(DEVICE_STATE_JOINING); - } - } -} - -void LoRaWANStack::mcps_confirm_handler() -{ - switch (_loramac.get_mcps_confirmation()->status) { - - case LORAMAC_EVENT_INFO_STATUS_OK: - _lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter; - send_event_to_application(TX_DONE); - break; - - case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: - tr_error("Fatal Error, Radio failed to transmit"); - send_event_to_application(TX_TIMEOUT); - break; - - case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: - send_event_to_application(TX_SCHEDULING_ERROR); - break; - - default: - // if no ack was received after enough retries, send TX_ERROR - send_event_to_application(TX_ERROR); - } -} - -void LoRaWANStack::mcps_indication_handler() -{ - const loramac_mcps_indication_t *mcps_indication = _loramac.get_mcps_indication(); - if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) { - tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status); - send_event_to_application(RX_ERROR); - return; - } - - _lw_session.downlink_counter = mcps_indication->dl_frame_counter; - - /** - * Check port, if it's compliance testing port and the compliance testing is - * not enabled, give up silently - */ - if (mcps_indication->port == COMPLIANCE_TESTING_PORT) { -#if !defined(LORAWAN_COMPLIANCE_TEST) - return; -#endif - } - - if (mcps_indication->is_data_recvd) { - // Valid message arrived. - _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; - _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size; - _rx_msg.msg.mcps_indication.port = mcps_indication->port; - _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer; - _rx_msg.msg.mcps_indication.type = mcps_indication->type; - - // Notify application about received frame.. - tr_debug("Packet Received %d bytes, Port=%d", - _rx_msg.msg.mcps_indication.buffer_size, - mcps_indication->port); - _rx_msg.receive_ready = true; - send_event_to_application(RX_DONE); - } - - /* - * If fPending bit is set we try to generate an empty packet - * with CONFIRMED flag set. We always set a CONFIRMED flag so - * that we could retry a certain number of times if the uplink - * failed for some reason - * or - * Class C and node received a confirmed message so we need to - * send an empty packet to acknowledge the message. - * This scenario is unspecified by LoRaWAN 1.0.2 specification, - * but version 1.1.0 says that network SHALL not send any new - * confirmed messages until ack has been sent - */ - if ((_loramac.get_device_class() != CLASS_C - && mcps_indication->fpending_status) - || (_loramac.get_device_class() == CLASS_C - && mcps_indication->type == MCPS_CONFIRMED)) { -#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE) - // Do not queue an automatic uplink of there is one already outgoing - // This means we have not received an ack for the previous automatic uplink - if (!_automatic_uplink_ongoing) { - tr_debug("Sending empty uplink message..."); - _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 - send_event_to_application(UPLINK_REQUIRED); -#endif - } -} - - -lorawan_status_t LoRaWANStack::state_controller(device_states_t new_state) -{ - lorawan_status_t status = LORAWAN_STATUS_OK; - - switch (new_state) { - case DEVICE_STATE_IDLE: - process_idle_state(status); - break; - case DEVICE_STATE_CONNECTING: - process_connecting_state(status); - break; - case DEVICE_STATE_JOINING: - process_joining_state(status); - break; - case DEVICE_STATE_CONNECTED: - process_connected_state(); - break; - case DEVICE_STATE_SCHEDULING: - process_scheduling_state(status); - break; - case DEVICE_STATE_STATUS_CHECK: - process_status_check_state(); - break; - case DEVICE_STATE_SHUTDOWN: - process_shutdown_state(status); - break; - default: - //Because this is internal function only coding error causes this - tr_error("Unknown state: %d:", new_state); - MBED_ASSERT(false); - } - - return status; -} - -void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status) -{ - /** - * Remove channels - * Radio will be put to sleep by the APIs underneath - */ - drop_channel_list(); - _loramac.disconnect(); - _lw_session.active = false; - _device_current_state = DEVICE_STATE_SHUTDOWN; - op_status = LORAWAN_STATUS_DEVICE_OFF; - _ctrl_flags = 0; - send_event_to_application(DISCONNECTED); -} - -void LoRaWANStack::process_status_check_state() -{ - if (_device_current_state == DEVICE_STATE_SENDING || - _device_current_state == DEVICE_STATE_AWAITING_ACK) { - // If there was a successful transmission, this block gets a kick after - // RX2 slot is exhausted. We may or may not have a successful UNCONFIRMED transmission - // here. In CONFIRMED case this block is invoked only - // when the MAX number of retries are exhausted, i.e., only error - // case will fall here. Moreover, it will happen for Class A only. - // Another possibility is the case when the stack fails to schedule a - // deferred transmission and a scheduling failure handler is invoked. - _ctrl_flags &= ~TX_DONE_FLAG; - _loramac.set_tx_ongoing(false); - _loramac.reset_ongoing_tx(); - mcps_confirm_handler(); - - } else if (_device_current_state == DEVICE_STATE_RECEIVING) { - - if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) { - _ctrl_flags &= ~TX_DONE_FLAG; - _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; - _loramac.set_tx_ongoing(false); - _loramac.reset_ongoing_tx(); - // if an automatic uplink is ongoing, we should not send a TX_DONE - // event to application - if (_automatic_uplink_ongoing) { - _automatic_uplink_ongoing = false; - } else { - mcps_confirm_handler(); - } - } - - // handle any received data and send event accordingly - if (_ctrl_flags & MSG_RECVD_FLAG) { - _ctrl_flags &= ~MSG_RECVD_FLAG; - mcps_indication_handler(); - } - } -} - -void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status) -{ - if (_device_current_state != DEVICE_STATE_IDLE) { - if (_device_current_state != DEVICE_STATE_RECEIVING - && _loramac.get_device_class() != CLASS_C) { - op_status = LORAWAN_STATUS_BUSY; - return; - } - } - - op_status = _loramac.send_ongoing_tx(); - if (op_status == LORAWAN_STATUS_OK) { - _ctrl_flags &= ~TX_DONE_FLAG; - _loramac.set_tx_ongoing(true); - _device_current_state = DEVICE_STATE_SENDING; - } -} - -void LoRaWANStack::process_joining_state(lorawan_status_t &op_status) -{ - if (_device_current_state == DEVICE_STATE_CONNECTING) { - _device_current_state = DEVICE_STATE_JOINING; - tr_debug("Sending Join Request ..."); - op_status = _loramac.join(true); - return; - } - - if (_device_current_state == DEVICE_STATE_AWAITING_JOIN_ACCEPT && - _loramac.get_current_slot() != RX_SLOT_WIN_1) { - _device_current_state = DEVICE_STATE_JOINING; - // retry join - bool can_continue = _loramac.continue_joining_process(); - - if (!can_continue) { - _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; - send_event_to_application(JOIN_FAILURE); - _device_current_state = DEVICE_STATE_IDLE; - return; - } - } -} - -void LoRaWANStack::process_connected_state() -{ - _ctrl_flags |= CONNECTED_FLAG; - _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; - - if (_ctrl_flags & USING_OTAA_FLAG) { - tr_debug("OTAA Connection OK!"); - } - - _lw_session.active = true; - send_event_to_application(CONNECTED); - - _device_current_state = DEVICE_STATE_IDLE; -} - -void LoRaWANStack::process_connecting_state(lorawan_status_t &op_status) -{ - MBED_ASSERT(_device_current_state == DEVICE_STATE_IDLE || - _device_current_state == DEVICE_STATE_SHUTDOWN); - - _device_current_state = DEVICE_STATE_CONNECTING; - - if (_ctrl_flags & USING_OTAA_FLAG) { - process_joining_state(op_status); - return; - } - - op_status = _loramac.join(false); - tr_debug("ABP connection OK."); - process_connected_state(); -} - -void LoRaWANStack::process_idle_state(lorawan_status_t &op_status) -{ - if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { - _device_current_state = DEVICE_STATE_IDLE; - process_uninitialized_state(op_status); - return; - } - - _device_current_state = DEVICE_STATE_IDLE; - op_status = LORAWAN_STATUS_OK; -} - -void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status) -{ - op_status = _loramac.initialize(_queue, mbed::callback(this, - &LoRaWANStack::handle_scheduling_failure)); - - if (op_status == LORAWAN_STATUS_OK) { - _device_current_state = DEVICE_STATE_IDLE; - } -} diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h deleted file mode 100644 index dbdcac0..0000000 --- a/features/lorawan/LoRaWANStack.h +++ /dev/null @@ -1,517 +0,0 @@ -/** - * \file LoRaWANStack.h - * - * \brief LoRaWAN stack layer implementation - * - * \copyright Revised BSD License, see LICENSE.TXT file include in the project - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * \author Miguel Luis ( Semtech ) - * - * \author Gregory Cristian ( Semtech ) - * - * \author Daniel Jaeckle ( STACKFORCE ) - * - * \defgroup LoRaWAN stack layer that controls MAC layer underneath - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Copyright (c) 2017, Arm Limited and affiliates. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef LORAWANSTACK_H_ -#define LORAWANSTACK_H_ - -#include -#include "events/EventQueue.h" -#include "platform/mbed_atomic.h" -#include "platform/Callback.h" -#include "platform/NonCopyable.h" -#include "platform/ScopedLock.h" - -#include "lorastack/mac/LoRaMac.h" -#include "system/LoRaWANTimer.h" -#include "system/lorawan_data_structures.h" -#include "LoRaRadio.h" - -class LoRaPHY; - -/** LoRaWANStack Class - * A controller layer for LoRaWAN MAC and PHY - */ -class LoRaWANStack: private mbed::NonCopyable { - -public: - LoRaWANStack(); - - /** Binds PHY layer and radio driver to stack. - * - * MAC layer is totally detached from the PHY layer so the stack layer - * needs to play the role of an arbitrator. - * This API sets the PHY layer object to stack and bind the radio driver - * object from the application to the PHY layer. - * Also initialises radio callback handles which the radio driver will - * use in order to report events. - * - * @param radio LoRaRadio object, i.e., the radio driver - * @param phy LoRaPHY object. - * - */ - void bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy); - - /** End device initialization. - * @param queue A pointer to an EventQueue passed from the application. - * @return LORAWAN_STATUS_OK on success, a negative error code on failure. - */ - lorawan_status_t initialize_mac_layer(events::EventQueue *queue); - - /** Sets all callbacks for the application. - * - * @param callbacks A pointer to the structure carrying callbacks. - * @return LORAWAN_STATUS_OK on success, a negative error code on failure. - */ - lorawan_status_t set_lora_callbacks(const lorawan_app_callbacks_t *callbacks); - - /** Connect OTAA or ABP using Mbed-OS config system - * - * @return For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed by - * a 'CONNECTED' event. Otherwise a negative error code is returned. - * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. - * - * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the first call. - * Any subsequent call will return either LORAWAN_STATUS_BUSY (if the previous request for connection - * is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). - * A 'CONNECTED' event is sent to the application when the JoinAccept is received. - */ - lorawan_status_t connect(); - - /** Connect OTAA or ABP with parameters - * - * @param connect Options for an end device connection to the gateway. - * - * @return For ABP: If everything goes well, LORAWAN_STATUS_OK is returned for first call followed by - * a 'CONNECTED' event. Otherwise a negative error code is returned. - * Any subsequent call will return LORAWAN_STATUS_ALREADY_CONNECTED and no event follows. - * - * For OTAA: When a JoinRequest is sent, LORAWAN_STATUS_CONNECT_IN_PROGRESS is returned for the first call. - * Any subsequent call will return either LORAWAN_STATUS_BUSY (if the previous request for connection - * is still underway) or LORAWAN_STATUS_ALREADY_CONNECTED (if a network was already joined successfully). - * A 'CONNECTED' event is sent to the application when the JoinAccept is received. - */ - lorawan_status_t connect(const lorawan_connect_t &connect); - - /** Adds channels to use. - * - * You can provide a list of channels with appropriate parameters filled - * in. However, this list is not absolute. In some regions, a CF - * list gets implemented by default, which means that the network can overwrite your channel - * frequency settings right after receiving a Join Accept. You may try - * to set up any channel or channels after that and if the channel requested - * is already active, the request is silently ignored. A negative error - * code is returned if there is any problem with parameters. - * - * You need to ensure that the base station nearby supports the channel or channels being added. - * - * If your list includes a default channel (a channel where Join Requests - * are received) you cannot fully configure the channel parameters. - * Either leave the channel settings to default or check your - * corresponding PHY layer implementation. For example, LoRaPHYE868. - * - * @param channel_plan A list of channels or a single channel. - * - * @return LORAWAN_STATUS_OK on success, a negative error - * code on failure. - */ - lorawan_status_t add_channels(const lorawan_channelplan_t &channel_plan); - - /** Removes a channel from the list. - * - * @param channel_id Index of the channel being removed - * - * @return LORAWAN_STATUS_OK on success, a negative error - * code on failure. - */ - lorawan_status_t remove_a_channel(uint8_t channel_id); - - /** Removes a previously set channel plan. - * - * @return LORAWAN_STATUS_OK on success, a negative error - * code on failure. - */ - lorawan_status_t drop_channel_list(); - - /** Gets a list of currently enabled channels . - * - * @param channel_plan The channel plan structure to store final result. - * - * @return LORAWAN_STATUS_OK on success, a negative error - * code on failure. - */ - lorawan_status_t get_enabled_channels(lorawan_channelplan_t &channel_plan); - - /** Sets up a retry counter for confirmed messages. - * - * Valid only for confirmed messages. This API sets the number of times the - * stack will retry a CONFIRMED message before giving up and reporting an - * error. - * - * @param count The number of retries for confirmed messages. - * - * @return LORAWAN_STATUS_OK or a negative error code. - */ - lorawan_status_t set_confirmed_msg_retry(uint8_t count); - - /** Sets up the data rate. - * - * `set_datarate()` first verifies whether the data rate given is valid or not. - * If it is valid, the system sets the given data rate to the channel. - * - * @param data_rate The intended data rate, for example DR_0 or DR_1. - * Note that the macro DR_* can mean different - * things in different regions. - * - * @return LORAWAN_STATUS_OK if everything goes well, otherwise - * a negative error code. - */ - lorawan_status_t set_channel_data_rate(uint8_t data_rate); - - /** Enables ADR. - * - * @param adr_enabled 0 ADR disabled, 1 ADR enabled. - * - * @return LORAWAN_STATUS_OK on success, a negative error - * code on failure. - */ - lorawan_status_t enable_adaptive_datarate(bool adr_enabled); - - /** Send message to gateway - * - * @param port The application port number. Port numbers 0 and 224 - * are reserved, whereas port numbers from 1 to 223 - * (0x01 to 0xDF) are valid port numbers. - * Anything out of this range is illegal. - * - * @param data A pointer to the data being sent. The ownership of the - * buffer is not transferred. The data is copied to the - * internal buffers. - * - * @param length The size of data in bytes. - * - * @param flags A flag used to determine what type of - * message is being sent, for example: - * - * MSG_UNCONFIRMED_FLAG = 0x01 - * MSG_CONFIRMED_FLAG = 0x02 - * MSG_MULTICAST_FLAG = 0x04 - * MSG_PROPRIETARY_FLAG = 0x08 - * MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be - * used in conjunction with MSG_UNCONFIRMED_FLAG and - * MSG_CONFIRMED_FLAG depending on the intended use. - * - * MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set - * a confirmed message flag for a proprietary message. - * MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are - * mutually exclusive. - * - * @param null_allowed Internal use only. Needed for sending empty packet - * having CONFIRMED bit on. - * - * @param allow_port_0 Internal use only. Needed for flushing MAC commands. - * - * @return The number of bytes sent, or - * LORAWAN_STATUS_WOULD_BLOCK if another TX is - * ongoing, or a negative error code on failure. - */ - int16_t handle_tx(uint8_t port, const uint8_t *data, - uint16_t length, uint8_t flags, - bool null_allowed = false, bool allow_port_0 = false); - - /** Receives a message from the Network Server. - * - * @param data A pointer to buffer where the received data will be - * stored. - * - * @param length The size of data in bytes - * - * @param port The application port number. Port numbers 0 and 224 - * are reserved, whereas port numbers from 1 to 223 - * (0x01 to 0xDF) are valid port numbers. - * Anything out of this range is illegal. - * - * In return will contain the number of port to which - * message was received. - * - * @param flags A flag is used to determine what type of - * message is being received, for example: - * - * MSG_UNCONFIRMED_FLAG = 0x01, - * MSG_CONFIRMED_FLAG = 0x02 - * MSG_MULTICAST_FLAG = 0x04, - * MSG_PROPRIETARY_FLAG = 0x08 - * - * MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be - * used in conjunction with MSG_UNCONFIRMED_FLAG and - * MSG_CONFIRMED_FLAG depending on the intended use. - * - * MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set - * a confirmed message flag for a proprietary message. - * - * MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are - * not mutually exclusive, i.e., the user can subscribe to - * receive both CONFIRMED AND UNCONFIRMED messages at - * the same time. - * - * In return will contain the flags to determine what kind - * of message was received. - * - * @param validate_params If set to true, the given port and flags values will be checked - * against the values received with the message. If values do not - * match, LORAWAN_STATUS_WOULD_BLOCK will be returned. - * - * @return It could be one of these: - * i) 0 if there is nothing else to read. - * ii) Number of bytes written to user buffer. - * iii) LORAWAN_STATUS_WOULD_BLOCK if there is - * nothing available to read at the moment. - * iv) A negative error code on failure. - */ - int16_t handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params); - - /** Send Link Check Request MAC command. - * - * - * This API schedules a Link Check Request command (LinkCheckReq) for the network - * server and once the response, i.e., LinkCheckAns MAC command is received - * from the Network Server, an event is generated. - * - * A callback function for the link check response must be set prior to using - * this API, otherwise a LORAWAN_STATUS_PARAMETER_INVALID error is thrown. - * - * @return LORAWAN_STATUS_OK on successfully queuing a request, or - * a negative error code on failure. - * - */ - lorawan_status_t set_link_check_request(); - - /** Removes link check request sticky MAC command. - * - * Any already queued request may still get entertained. However, no new - * requests will be made. - */ - void remove_link_check_request(); - - /** Shuts down the LoRaWAN protocol. - * - * In response to the user call for disconnection, the stack shuts down itself. - * - * @return LORAWAN_STATUS_DEVICE_OFF on successfully shutdown. - */ - lorawan_status_t shutdown(); - - /** Change device class - * - * Change current device class. - * - * @param device_class The device class - * - * @return LORAWAN_STATUS_OK on success, - * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, - * or other negative error code if request failed. - */ - lorawan_status_t set_device_class(const device_class_t &device_class); - - /** Acquire TX meta-data - * - * Upon successful transmission, TX meta-data will be made available - * - * @param metadata A reference to the inbound structure which will be - * filled with any TX meta-data if available. - * - * @return LORAWAN_STATUS_OK if successful, - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise - */ - lorawan_status_t acquire_tx_metadata(lorawan_tx_metadata &metadata); - - /** Acquire RX meta-data - * - * Upon successful reception, RX meta-data will be made available - * - * @param metadata A reference to the inbound structure which will be - * filled with any RX meta-data if available. - * - * @return LORAWAN_STATUS_OK if successful, - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise - */ - lorawan_status_t acquire_rx_metadata(lorawan_rx_metadata &metadata); - - /** Acquire backoff meta-data - * - * Get hold of backoff time after which the transmission will take place. - * - * @param backoff A reference to the inbound integer which will be - * filled with any backoff meta-data if available. - * - * @return LORAWAN_STATUS_OK if successful, - * LORAWAN_STATUS_METADATA_NOT_AVAILABLE otherwise - */ - lorawan_status_t acquire_backoff_metadata(int &backoff); - - /** Stops sending - * - * Stop sending any outstanding messages if they are not yet queued for - * transmission, i.e., if the backoff timer is nhot elapsed yet. - * - * @return LORAWAN_STATUS_OK if the transmission is cancelled. - * LORAWAN_STATUS_BUSY otherwise. - */ - lorawan_status_t stop_sending(void); - - void lock(void) - { - _loramac.lock(); - } - void unlock(void) - { - _loramac.unlock(); - } - -private: - typedef mbed::ScopedLock Lock; - /** - * Checks if the user provided port is valid or not - */ - bool is_port_valid(uint8_t port, bool allow_port_0 = false); - - /** - * State machine for stack controller layer. - */ - lorawan_status_t state_controller(device_states_t new_state); - - /** - * Helpers for state controller - */ - void process_uninitialized_state(lorawan_status_t &op_status); - void process_idle_state(lorawan_status_t &op_status); - void process_connected_state(); - void process_connecting_state(lorawan_status_t &op_status); - void process_joining_state(lorawan_status_t &op_status); - void process_scheduling_state(lorawan_status_t &op_status); - void process_status_check_state(); - void process_shutdown_state(lorawan_status_t &op_status); - void state_machine_run_to_completion(void); - - /** - * Handles MLME indications - */ - void mlme_indication_handler(void); - - /** - * Handles an MLME confirmation - */ - void mlme_confirm_handler(void); - - /** - * Handles an MCPS confirmation - */ - void mcps_confirm_handler(void); - - /** - * Handles an MCPS indication - */ - void mcps_indication_handler(void); - - /** - * Sets up user application port - */ - lorawan_status_t set_application_port(uint8_t port, bool allow_port_0 = false); - - /** - * Handles connection internally - */ - lorawan_status_t handle_connect(bool is_otaa); - - - /** Send event to application. - * - * @param event The event to be sent. - */ - void send_event_to_application(const lorawan_event_t event) const; - - /** Send empty uplink message to network. - * - * Sends an empty confirmed message to gateway. - * - * @param port The event to be sent. - */ - void send_automatic_uplink_message(uint8_t port); - - /** - * TX interrupt handlers and corresponding processors - */ - void tx_interrupt_handler(void); - void tx_timeout_interrupt_handler(void); - void process_transmission(void); - void process_transmission_timeout(void); - - /** - * RX interrupt handlers and corresponding processors - */ - void rx_interrupt_handler(const uint8_t *payload, uint16_t size, int16_t rssi, - int8_t snr); - void rx_timeout_interrupt_handler(void); - void rx_error_interrupt_handler(void); - void process_reception(const uint8_t *payload, uint16_t size, int16_t rssi, - int8_t snr); - void process_reception_timeout(bool is_timeout); - - int convert_to_msg_flag(const mcps_type_t type); - - void make_tx_metadata_available(void); - void make_rx_metadata_available(void); - - void handle_scheduling_failure(void); - - void post_process_tx_with_reception(void); - void post_process_tx_no_reception(void); - -private: - LoRaMac _loramac; - radio_events_t radio_events; - device_states_t _device_current_state; - lorawan_app_callbacks_t _callbacks; - lorawan_session_t _lw_session; - loramac_tx_message_t _tx_msg; - loramac_rx_message_t _rx_msg; - lorawan_tx_metadata _tx_metadata; - lorawan_rx_metadata _rx_metadata; - uint8_t _num_retry; - uint8_t _qos_cnt; - uint32_t _ctrl_flags; - uint8_t _app_port; - bool _link_check_requested; - bool _automatic_uplink_ongoing; - core_util_atomic_flag _rx_payload_in_use; - uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD]; - events::EventQueue *_queue; - lorawan_time_t _tx_timestamp; -}; - -#endif /* LORAWANSTACK_H_ */ diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp deleted file mode 100644 index 6f0f0b1..0000000 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ /dev/null @@ -1,1991 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRa MAC layer implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ -#include -#include -#include "LoRaMac.h" - -#include "mbed-trace/mbed_trace.h" -#define TRACE_GROUP "LMAC" - -using namespace events; -using namespace mbed; - -/* - * LoRaWAN spec 6.2: AppKey is AES-128 key - */ -#define APPKEY_KEY_LENGTH 128 - -/*! - * Maximum length of the fOpts field - */ -#define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH 15 - -/*! - * LoRaMac duty cycle for the back-off procedure during the first hour. - */ -#define BACKOFF_DC_1_HOUR 100 - -/*! - * LoRaMac duty cycle for the back-off procedure during the next 10 hours. - */ -#define BACKOFF_DC_10_HOURS 1000 - -/*! - * LoRaMac duty cycle for the back-off procedure during the next 24 hours. - */ -#define BACKOFF_DC_24_HOURS 10000 - -/*! - * The frame direction definition for uplink communications. - */ -#define UP_LINK 0 - -/*! - * The frame direction definition for downlink communications. - */ -#define DOWN_LINK 1 - -LoRaMac::LoRaMac() - : _lora_time(), - _lora_phy(NULL), - _mac_commands(), - _channel_plan(), - _lora_crypto(), - _params(), - _ev_queue(NULL), - _mcps_indication(), - _mcps_confirmation(), - _mlme_indication(), - _mlme_confirmation(), - _ongoing_tx_msg(), - _is_nwk_joined(false), - _can_cancel_tx(true), - _continuous_rx2_window_open(false), - _device_class(CLASS_A), - _prev_qos_level(LORAWAN_DEFAULT_QOS), - _demod_ongoing(false) -{ - _params.is_rx_window_enabled = true; - _params.max_ack_timeout_retries = 1; - _params.ack_timeout_retry_counter = 1; - - reset_mcps_confirmation(); - reset_mlme_confirmation(); - reset_mcps_indication(); -} - -LoRaMac::~LoRaMac() -{ -} - -/*************************************************************************** - * Radio event callbacks - delegated to Radio driver * - **************************************************************************/ - -const loramac_mcps_confirm_t *LoRaMac::get_mcps_confirmation() const -{ - return &_mcps_confirmation; -} - -const loramac_mcps_indication_t *LoRaMac::get_mcps_indication() const -{ - return &_mcps_indication; -} - -const loramac_mlme_confirm_t *LoRaMac::get_mlme_confirmation() const -{ - return &_mlme_confirmation; -} - -const loramac_mlme_indication_t *LoRaMac::get_mlme_indication() const -{ - return &_mlme_indication; -} - -void LoRaMac::post_process_mlme_request() -{ - _mlme_confirmation.pending = false; -} - -void LoRaMac::post_process_mcps_req() -{ - _params.is_last_tx_join_request = false; - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; - if (_mcps_confirmation.req_type == MCPS_CONFIRMED) { - // An MCPS request for a CONFIRMED message has received an ack - // in the downlink message - if (_mcps_confirmation.ack_received) { - _params.is_node_ack_requested = false; - _mcps_confirmation.ack_received = false; - _mcps_indication.is_ack_recvd = false; - } else { - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - } - - _params.ul_frame_counter++; - _params.adr_ack_counter++; - } else { - //UNCONFIRMED or PROPRIETARY - _params.ul_frame_counter++; - _params.adr_ack_counter++; - if (_params.sys_params.nb_trans > 1) { - _mcps_confirmation.nb_retries = _params.ul_nb_rep_counter; - } - } -} - -void LoRaMac::post_process_mcps_ind() -{ - _mcps_indication.pending = false; -} - -void LoRaMac::post_process_mlme_ind() -{ - _mlme_indication.pending = false; -} - -lorawan_time_t LoRaMac::get_current_time(void) -{ - return _lora_time.get_current_time(); -} - -rx_slot_t LoRaMac::get_current_slot(void) -{ - return _params.rx_slot; -} - -/** - * This part handles incoming frames in response to Radio RX Interrupt - */ -void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size) -{ - uint32_t mic = 0; - uint32_t mic_rx = 0; - - _mlme_confirmation.nb_retries = _params.join_request_trial_counter; - - if (0 != _lora_crypto.decrypt_join_frame(payload + 1, size - 1, - _params.keys.app_key, APPKEY_KEY_LENGTH, - _params.rx_buffer + 1)) { - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - return; - } - - _params.rx_buffer[0] = payload[0]; - - if (_lora_crypto.compute_join_frame_mic(_params.rx_buffer, - size - LORAMAC_MFR_LEN, - _params.keys.app_key, - APPKEY_KEY_LENGTH, - &mic) != 0) { - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - return; - } - - mic_rx |= (uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN]; - mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 1] << 8); - mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 2] << 16); - mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 3] << 24); - - if (mic_rx == mic) { - _lora_time.stop(_params.timers.rx_window2_timer); - if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key, - APPKEY_KEY_LENGTH, - _params.rx_buffer + 1, - _params.dev_nonce, - _params.keys.nwk_skey, - _params.keys.app_skey) != 0) { - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - return; - } - - _params.net_id = (uint32_t) _params.rx_buffer[4]; - _params.net_id |= ((uint32_t) _params.rx_buffer[5] << 8); - _params.net_id |= ((uint32_t) _params.rx_buffer[6] << 16); - - _params.dev_addr = (uint32_t) _params.rx_buffer[7]; - _params.dev_addr |= ((uint32_t) _params.rx_buffer[8] << 8); - _params.dev_addr |= ((uint32_t) _params.rx_buffer[9] << 16); - _params.dev_addr |= ((uint32_t) _params.rx_buffer[10] << 24); - - _params.sys_params.rx1_dr_offset = (_params.rx_buffer[11] >> 4) & 0x07; - _params.sys_params.rx2_channel.datarate = _params.rx_buffer[11] & 0x0F; - - _params.sys_params.recv_delay1 = (_params.rx_buffer[12] & 0x0F); - - if (_params.sys_params.recv_delay1 == 0) { - _params.sys_params.recv_delay1 = 1; - } - - _params.sys_params.recv_delay1 *= 1000; - _params.sys_params.recv_delay2 = _params.sys_params.recv_delay1 + 1000; - - // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC - _lora_phy->apply_cf_list(&_params.rx_buffer[13], size - 17); - - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; - _is_nwk_joined = true; - // Node joined successfully - _params.ul_frame_counter = 0; - _params.ul_nb_rep_counter = 0; - _params.adr_ack_counter = 0; - - } else { - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; - } -} - -void LoRaMac::check_frame_size(uint16_t size) -{ - uint8_t value = _lora_phy->get_max_payload(_mcps_indication.rx_datarate, - _params.is_repeater_supported); - - if (MAX(0, (int16_t)((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD)) - > (int32_t) value) { - tr_error("Invalid frame size"); - } -} - -bool LoRaMac::message_integrity_check(const uint8_t *const payload, - const uint16_t size, - uint8_t *const ptr_pos, - uint32_t address, - uint32_t *downlink_counter, - const uint8_t *nwk_skey) -{ - uint32_t mic = 0; - uint32_t mic_rx = 0; - - uint16_t sequence_counter = 0; - uint16_t sequence_counter_prev = 0; - uint16_t sequence_counter_diff = 0; - - sequence_counter = (uint16_t) payload[(*ptr_pos)++]; - sequence_counter |= (uint16_t) payload[(*ptr_pos)++] << 8; - - mic_rx |= (uint32_t) payload[size - LORAMAC_MFR_LEN]; - mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 1] << 8); - mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 2] << 16); - mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 3] << 24); - - sequence_counter_prev = (uint16_t) * downlink_counter; - sequence_counter_diff = sequence_counter - sequence_counter_prev; - *downlink_counter += sequence_counter_diff; - - if (sequence_counter_diff >= _lora_phy->get_maximum_frame_counter_gap()) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOST; - _mcps_indication.dl_frame_counter = *downlink_counter; - return false; - } - - // sizeof nws_skey must be the same as _params.keys.nwk_skey, - _lora_crypto.compute_mic(payload, size - LORAMAC_MFR_LEN, - nwk_skey, - sizeof(_params.keys.nwk_skey) * 8, - address, DOWN_LINK, *downlink_counter, &mic); - - if (mic_rx != mic) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; - return false; - } - - return true; -} - -void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload, - uint16_t size, - uint8_t fopts_len, - uint8_t *nwk_skey, - uint8_t *app_skey, - uint32_t address, - uint32_t downlink_counter, - int16_t rssi, - int8_t snr) -{ - uint8_t frame_len = 0; - uint8_t payload_start_index = 8 + fopts_len; - uint8_t port = payload[payload_start_index++]; - frame_len = (size - 4) - payload_start_index; - - _mcps_indication.port = port; - - // special handling of control port 0 - if (port == 0) { - if (fopts_len == 0) { - // sizeof nws_skey must be the same as _params.keys.nwk_skey, - if (_lora_crypto.decrypt_payload(payload + payload_start_index, - frame_len, - nwk_skey, - sizeof(_params.keys.nwk_skey) * 8, - address, - DOWN_LINK, - downlink_counter, - _params.rx_buffer) != 0) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - } - - if (_mac_commands.process_mac_commands(_params.rx_buffer, 0, frame_len, - snr, _mlme_confirmation, - _params.sys_params, *_lora_phy) - != LORAWAN_STATUS_OK) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - return; - } - - if (_mac_commands.has_sticky_mac_cmd()) { - set_mlme_schedule_ul_indication(); - _mac_commands.clear_sticky_mac_cmd(); - } - - return; - } - - _mcps_indication.pending = false; - _mcps_confirmation.ack_received = false; - _mcps_indication.is_ack_recvd = false; - - return; - } - - // normal unicast/multicast port handling - if (fopts_len > 0) { - // Decode Options field MAC commands. Omit the fPort. - if (_mac_commands.process_mac_commands(payload, 8, - payload_start_index - 1, - snr, - _mlme_confirmation, - _params.sys_params, - *_lora_phy) != LORAWAN_STATUS_OK) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - return; - } - - if (_mac_commands.has_sticky_mac_cmd()) { - set_mlme_schedule_ul_indication(); - _mac_commands.clear_sticky_mac_cmd(); - } - } - - // sizeof app_skey must be the same as _params.keys.app_skey - if (_lora_crypto.decrypt_payload(payload + payload_start_index, - frame_len, - app_skey, - sizeof(_params.keys.app_skey) * 8, - address, - DOWN_LINK, - downlink_counter, - _params.rx_buffer) != 0) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; - } else { - _mcps_indication.buffer = _params.rx_buffer; - _mcps_indication.buffer_size = frame_len; - _mcps_indication.is_data_recvd = true; - } -} - -void LoRaMac::extract_mac_commands_only(const uint8_t *payload, - int8_t snr, - uint8_t fopts_len) -{ - uint8_t payload_start_index = 8 + fopts_len; - if (fopts_len > 0) { - if (_mac_commands.process_mac_commands(payload, 8, payload_start_index, - snr, _mlme_confirmation, - _params.sys_params, *_lora_phy) - != LORAWAN_STATUS_OK) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - return; - } - - if (_mac_commands.has_sticky_mac_cmd()) { - set_mlme_schedule_ul_indication(); - _mac_commands.clear_sticky_mac_cmd(); - } - } -} - -void LoRaMac::handle_data_frame(const uint8_t *const payload, - const uint16_t size, - uint8_t ptr_pos, - uint8_t msg_type, - int16_t rssi, - int8_t snr) -{ - check_frame_size(size); - - bool is_multicast = false; - loramac_frame_ctrl_t fctrl; - multicast_params_t *cur_multicast_params; - uint32_t address = 0; - uint32_t downlink_counter = 0; - uint8_t app_payload_start_index = 0; - uint8_t *nwk_skey = _params.keys.nwk_skey; - uint8_t *app_skey = _params.keys.app_skey; - - address = payload[ptr_pos++]; - address |= ((uint32_t) payload[ptr_pos++] << 8); - address |= ((uint32_t) payload[ptr_pos++] << 16); - address |= ((uint32_t) payload[ptr_pos++] << 24); - - if (address != _params.dev_addr) { - // check if Multicast is destined for us - cur_multicast_params = _params.multicast_channels; - - while (cur_multicast_params != NULL) { - if (address == cur_multicast_params->address) { - is_multicast = true; - nwk_skey = cur_multicast_params->nwk_skey; - app_skey = cur_multicast_params->app_skey; - downlink_counter = cur_multicast_params->dl_frame_counter; - break; - } - - cur_multicast_params = cur_multicast_params->next; - } - - if (!is_multicast) { - // We are not the destination of this frame. - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; - _mcps_indication.pending = false; - return; - } - } else { - is_multicast = false; - nwk_skey = _params.keys.nwk_skey; - app_skey = _params.keys.app_skey; - downlink_counter = _params.dl_frame_counter; - } - - fctrl.value = payload[ptr_pos++]; - app_payload_start_index = 8 + fctrl.bits.fopts_len; - - //perform MIC check - if (!message_integrity_check(payload, size, &ptr_pos, address, - &downlink_counter, nwk_skey)) { - tr_error("MIC failed"); - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; - _mcps_indication.pending = false; - return; - } - - _mcps_confirmation.ack_received = false; - _mcps_indication.is_ack_recvd = false; - _mcps_indication.pending = true; - _mcps_indication.is_data_recvd = false; - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; - _mcps_indication.multicast = is_multicast; - _mcps_indication.fpending_status = fctrl.bits.fpending; - _mcps_indication.buffer = NULL; - _mcps_indication.buffer_size = 0; - _mcps_indication.dl_frame_counter = downlink_counter; - _mcps_indication.rssi = rssi; - _mcps_indication.snr = snr; - - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; - - _params.adr_ack_counter = 0; - _mac_commands.clear_repeat_buffer(); - _mac_commands.clear_command_buffer(); - - if (is_multicast) { - _mcps_indication.type = MCPS_MULTICAST; - - // Discard if its a repeated message - if ((cur_multicast_params->dl_frame_counter == downlink_counter) - && (cur_multicast_params->dl_frame_counter != 0)) { - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - _mcps_indication.dl_frame_counter = downlink_counter; - _mcps_indication.pending = false; - - return; - } - - cur_multicast_params->dl_frame_counter = downlink_counter; - - } else { - if (msg_type == FRAME_TYPE_DATA_CONFIRMED_DOWN) { - _params.is_srv_ack_requested = true; - _mcps_indication.type = MCPS_CONFIRMED; - - if ((_params.dl_frame_counter == downlink_counter) - && (_params.dl_frame_counter != 0)) { - // Duplicated confirmed downlink. Skip indication. - // In this case, the MAC layer shall accept the MAC commands - // which are included in the downlink retransmission. - // It should not provide the same frame to the application - // layer again. The MAC layer accepts the acknowledgement. - tr_debug("Discarding duplicate frame"); - _mcps_indication.pending = false; - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - - return; - } - } else if (msg_type == FRAME_TYPE_DATA_UNCONFIRMED_DOWN) { - _params.is_srv_ack_requested = false; - _mcps_indication.type = MCPS_UNCONFIRMED; - - if ((_params.dl_frame_counter == downlink_counter) - && (_params.dl_frame_counter != 0)) { - tr_debug("Discarding duplicate frame"); - _mcps_indication.pending = false; - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - - return; - } - } - _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) { - _mcps_confirmation.ack_received = fctrl.bits.ack; - _mcps_indication.is_ack_recvd = fctrl.bits.ack; - } - - uint8_t frame_len = (size - 4) - app_payload_start_index; - - if (frame_len > 0) { - extract_data_and_mac_commands(payload, size, fctrl.bits.fopts_len, - nwk_skey, app_skey, address, - downlink_counter, rssi, snr); - } else { - extract_mac_commands_only(payload, snr, fctrl.bits.fopts_len); - } - - // Handle proprietary messages. - if (msg_type == FRAME_TYPE_PROPRIETARY) { - memcpy(_params.rx_buffer, &payload[ptr_pos], size); - - _mcps_indication.type = MCPS_PROPRIETARY; - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; - _mcps_indication.buffer = _params.rx_buffer; - _mcps_indication.buffer_size = size - ptr_pos; - } - - // only stop act timer, if the ack is actually recieved - if (_mcps_confirmation.ack_received) { - _lora_time.stop(_params.timers.ack_timeout_timer); - } - - channel_params_t *list = _lora_phy->get_phy_channels(); - _mcps_indication.channel = list[_params.channel].frequency; - - if (get_current_slot() == RX_SLOT_WIN_1) { - _mcps_indication.rx_toa = _lora_phy->get_rx_time_on_air(_params.rx_window1_config.modem_type, - _mcps_indication.buffer_size); - } else { - _mcps_indication.rx_toa = _lora_phy->get_rx_time_on_air(_params.rx_window2_config.modem_type, - _mcps_indication.buffer_size); - } -} - -void LoRaMac::set_batterylevel_callback(mbed::Callback battery_level) -{ - _mac_commands.set_batterylevel_callback(battery_level); -} - -void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp) -{ - if (_device_class == CLASS_C) { - // this will open a continuous RX2 window until time==RECV_DELAY1 - open_rx2_window(); - } else { - _lora_phy->put_radio_to_sleep(); - } - - if ((_mcps_confirmation.req_type == MCPS_UNCONFIRMED) - && (_params.sys_params.nb_trans > 1)) { - //MBED_ASSERT(_params.ul_nb_rep_counter <= _params.sys_params.nb_trans); - _params.ul_nb_rep_counter++; - } - - if (_params.is_rx_window_enabled == true) { - lorawan_time_t time_diff = _lora_time.get_current_time() - timestamp; - // start timer after which rx1_window will get opened - _lora_time.start(_params.timers.rx_window1_timer, - _params.rx_window1_delay - time_diff); - - // start timer after which rx2_window will get opened - _lora_time.start(_params.timers.rx_window2_timer, - _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_ms); - } - - // start timer after which ack wait will timeout (for Confirmed messages) - if (_params.is_node_ack_requested) { - _lora_time.start(_params.timers.ack_timeout_timer, - (_params.rx_window2_delay - time_diff) + - _params.rx_window2_config.window_timeout_ms + - _lora_phy->get_ack_timeout()); - } - } else { - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - } - - _params.last_channel_idx = _params.channel; - - _lora_phy->set_last_tx_done(_params.channel, _is_nwk_joined, timestamp); - - _params.timers.aggregated_last_tx_time = timestamp; - - _mac_commands.clear_command_buffer(); -} - -void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size, - int16_t rssi, int8_t snr) -{ - _demod_ongoing = false; - if (_device_class == CLASS_C && !_continuous_rx2_window_open) { - _lora_time.stop(_rx2_closure_timer_for_class_c); - open_rx2_window(); - } else if (_device_class != CLASS_C) { - _lora_time.stop(_params.timers.rx_window1_timer); - _lora_phy->put_radio_to_sleep(); - } - - loramac_mhdr_t mac_hdr; - uint8_t pos = 0; - mac_hdr.value = payload[pos++]; - - switch (mac_hdr.bits.mtype) { - - case FRAME_TYPE_JOIN_ACCEPT: - - if (nwk_joined()) { - _mlme_confirmation.pending = false; - return; - } else { - handle_join_accept_frame(payload, size); - _mlme_confirmation.pending = true; - } - - break; - - case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: - case FRAME_TYPE_DATA_CONFIRMED_DOWN: - case FRAME_TYPE_PROPRIETARY: - - handle_data_frame(payload, size, pos, mac_hdr.bits.mtype, rssi, snr); - - break; - - default: - // This can happen e.g. if we happen to receive uplink of another device - // during the receive window. Block RX2 window since it can overlap with - // QOS TX and cause a mess. - tr_debug("RX unexpected mtype %u", mac_hdr.bits.mtype); - if (get_current_slot() == RX_SLOT_WIN_1) { - _lora_time.stop(_params.timers.rx_window2_timer); - } - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; - _mcps_indication.pending = false; - break; - } -} - -void LoRaMac::on_radio_tx_timeout(void) -{ - _lora_time.stop(_params.timers.rx_window1_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); - - if (_device_class == CLASS_C) { - open_rx2_window(); - } else { - _lora_phy->put_radio_to_sleep(); - } - - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - - _mac_commands.clear_command_buffer(); - - 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.tx_toa = 0; -} - -void LoRaMac::on_radio_rx_timeout(bool is_timeout) -{ - _demod_ongoing = false; - if (_device_class == CLASS_A) { - _lora_phy->put_radio_to_sleep(); - } - - if (_params.rx_slot == RX_SLOT_WIN_1) { - if (_params.is_node_ack_requested == true) { - _mcps_confirmation.status = is_timeout ? - LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT : - LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; - } - _mlme_confirmation.status = is_timeout ? - LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT : - LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; - - if (_device_class != CLASS_C) { - if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { - _lora_time.stop(_params.timers.rx_window2_timer); - } - } - } else { - if (_params.is_node_ack_requested == true) { - _mcps_confirmation.status = is_timeout ? - LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT : - LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - } - - _mlme_confirmation.status = is_timeout ? - LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT : - LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - } -} - -bool LoRaMac::continue_joining_process() -{ - if (_params.join_request_trial_counter >= _params.max_join_request_trials) { - return false; - } - - // Schedule a retry - if (handle_retransmission() != LORAWAN_STATUS_CONNECT_IN_PROGRESS) { - return false; - } - - return true; -} - -bool LoRaMac::continue_sending_process() -{ - if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { - _lora_time.stop(_params.timers.ack_timeout_timer); - return false; - } - - // retransmission will be handled in on_ack_timeout() whence the ACK timeout - // gets fired - return true; -} - -lorawan_status_t LoRaMac::send_join_request() -{ - lorawan_status_t status = LORAWAN_STATUS_OK; - loramac_mhdr_t mac_hdr; - loramac_frame_ctrl_t fctrl; - - _params.sys_params.channel_data_rate = - _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); - - mac_hdr.value = 0; - mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ; - - fctrl.value = 0; - fctrl.bits.adr = _params.sys_params.adr_on; - _params.is_last_tx_join_request = true; - - /* In case of join request retransmissions, the stack must prepare - * the frame again, because the network server keeps track of the random - * LoRaMacDevNonce values to prevent reply attacks. */ - status = prepare_frame(&mac_hdr, &fctrl, 0, NULL, 0); - - if (status == LORAWAN_STATUS_OK) { - if (schedule_tx() == LORAWAN_STATUS_OK) { - status = LORAWAN_STATUS_CONNECT_IN_PROGRESS; - } - } else { - tr_error("Couldn't send a JoinRequest: error %d", status); - } - - return status; -} - -/** - * This function handles retransmission of failed or unacknowledged - * outgoing traffic - */ -lorawan_status_t LoRaMac::handle_retransmission() -{ - if (!nwk_joined() && (_mlme_confirmation.req_type == MLME_JOIN)) { - return send_join_request(); - } - - return schedule_tx(); -} - -/** - * This function is called when the backoff_timer gets fired. - * It is used for re-scheduling an unsent packet in the pipe. This packet - * can be a Join Request or any other data packet. - */ -void LoRaMac::on_backoff_timer_expiry(void) -{ - Lock lock(*this); - - _lora_time.stop(_params.timers.backoff_timer); - - if ((schedule_tx() != LORAWAN_STATUS_OK) && nwk_joined()) { - _scheduling_failure_handler.call(); - } -} - -void LoRaMac::open_rx1_window(void) -{ - Lock lock(*this); - _demod_ongoing = true; - _continuous_rx2_window_open = false; - _lora_time.stop(_params.timers.rx_window1_timer); - _params.rx_slot = RX_SLOT_WIN_1; - - channel_params_t *active_channel_list = _lora_phy->get_phy_channels(); - _params.rx_window1_config.channel = _params.channel; - _params.rx_window1_config.frequency = active_channel_list[_params.channel].frequency; - // Apply the alternative RX 1 window frequency, if it is available - if (active_channel_list[_params.channel].rx1_frequency != 0) { - _params.rx_window1_config.frequency = active_channel_list[_params.channel].rx1_frequency; - } - _params.rx_window1_config.dr_offset = _params.sys_params.rx1_dr_offset; - _params.rx_window1_config.dl_dwell_time = _params.sys_params.downlink_dwell_time; - _params.rx_window1_config.is_repeater_supported = _params.is_repeater_supported; - _params.rx_window1_config.is_rx_continuous = false; - _params.rx_window1_config.rx_slot = _params.rx_slot; - - if (_device_class == CLASS_C) { - _lora_phy->put_radio_to_standby(); - } - - _mcps_indication.rx_datarate = _params.rx_window1_config.datarate; - - _lora_phy->rx_config(&_params.rx_window1_config); - _lora_phy->handle_receive(); - - tr_debug("RX1 slot open, Freq = %lu", _params.rx_window1_config.frequency); -} - -void LoRaMac::open_rx2_window() -{ - if (_demod_ongoing) { - tr_info("RX1 Demodulation ongoing, skip RX2 window opening"); - return; - } - Lock lock(*this); - _continuous_rx2_window_open = true; - _lora_time.stop(_params.timers.rx_window2_timer); - - _params.rx_window2_config.channel = _params.channel; - _params.rx_window2_config.frequency = _params.sys_params.rx2_channel.frequency; - _params.rx_window2_config.dl_dwell_time = _params.sys_params.downlink_dwell_time; - _params.rx_window2_config.is_repeater_supported = _params.is_repeater_supported; - - if (get_device_class() == CLASS_C) { - _params.rx_window2_config.is_rx_continuous = true; - } else { - _params.rx_window2_config.is_rx_continuous = false; - } - - _params.rx_window2_config.rx_slot = _params.rx_window2_config.is_rx_continuous ? - RX_SLOT_WIN_CLASS_C : RX_SLOT_WIN_2; - - _mcps_indication.rx_datarate = _params.rx_window2_config.datarate; - - _lora_phy->rx_config(&_params.rx_window2_config); - _lora_phy->handle_receive(); - _params.rx_slot = _params.rx_window2_config.rx_slot; - - tr_debug("RX2 slot open, Freq = %lu", _params.rx_window2_config.frequency); -} - -void LoRaMac::on_ack_timeout_timer_event(void) -{ - Lock lock(*this); - - if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { - return; - } - - tr_debug("ACK_TIMEOUT Elapses, Retrying ..."); - _lora_time.stop(_params.timers.ack_timeout_timer); - - // reduce data rate on every 2nd attempt if and only if the - // ADR is on - if ((_params.ack_timeout_retry_counter % 2) - && (_params.sys_params.adr_on)) { - tr_debug("Trading datarate for range"); - _params.sys_params.channel_data_rate = _lora_phy->get_next_lower_tx_datarate(_params.sys_params.channel_data_rate); - } - - _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; - - - // Schedule a retry - lorawan_status_t status = handle_retransmission(); - - if (status == LORAWAN_STATUS_NO_CHANNEL_FOUND || - status == LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND) { - // In a case when enabled channels are not found, PHY layer - // resorts to default channels. Next attempt should go forward as the - // default channels are always available if there is a base station in the - // vicinity. Otherwise something is wrong with the stack, we should assert - // here - _mac_commands.clear_command_buffer(); - _params.is_node_ack_requested = false; - _mcps_confirmation.ack_received = false; - _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; - - // For the next attempt we need to make sure that we do not incur length error - // which would mean that the datarate changed during retransmissions and - // the original packet doesn't fit into allowed payload buffer anymore. - status = handle_retransmission(); - - if (status == LORAWAN_STATUS_LENGTH_ERROR) { - _scheduling_failure_handler.call(); - return; - } - - // if we did not incur a length error and still the status is not OK, - // it is a critical failure - status = handle_retransmission(); - MBED_ASSERT(status == LORAWAN_STATUS_OK); - (void) status; - } else if (status != LORAWAN_STATUS_OK) { - _scheduling_failure_handler.call(); - return; - } - - _params.ack_timeout_retry_counter++; -} - -bool LoRaMac::validate_payload_length(uint16_t length, - int8_t datarate, - uint8_t fopts_len) -{ - uint16_t max_value = 0; - uint16_t payloadSize = 0; - - max_value = _lora_phy->get_max_payload(datarate, _params.is_repeater_supported); - - // Calculate the resulting payload size - payloadSize = (length + fopts_len); - - // Validation of the application payload size - if ((payloadSize <= max_value) && - (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) { - return true; - } - return false; -} - -void LoRaMac::set_mlme_schedule_ul_indication(void) -{ - _mlme_indication.indication_type = MLME_SCHEDULE_UPLINK; - _mlme_indication.pending = true; -} - -// This is not actual transmission. It just schedules a message in response -// to MCPS request -lorawan_status_t LoRaMac::send(loramac_mhdr_t *machdr, const uint8_t fport, - const void *fbuffer, uint16_t fbuffer_size) -{ - loramac_frame_ctrl_t fctrl; - - fctrl.value = 0; - fctrl.bits.fopts_len = 0; - fctrl.bits.fpending = 0; - fctrl.bits.ack = false; - fctrl.bits.adr_ack_req = false; - fctrl.bits.adr = _params.sys_params.adr_on; - - lorawan_status_t status = prepare_frame(machdr, &fctrl, fport, fbuffer, - fbuffer_size); - - if (status != LORAWAN_STATUS_OK) { - return status; - } - - // Reset confirm parameters - _mcps_confirmation.nb_retries = 0; - _mcps_confirmation.ack_received = false; - _mcps_confirmation.ul_frame_counter = _params.ul_frame_counter; - - status = schedule_tx(); - - return status; -} - -int LoRaMac::get_backoff_timer_event_id(void) -{ - return _params.timers.backoff_timer.timer_id; -} - -lorawan_status_t LoRaMac::clear_tx_pipe(void) -{ - if (!_can_cancel_tx) { - return LORAWAN_STATUS_BUSY; - } - - // check if the event is not already queued - const int id = get_backoff_timer_event_id(); - - if (id == 0) { - // No queued send request - return LORAWAN_STATUS_NO_OP; - } - - if (_ev_queue->time_left(id) > 0) { - _lora_time.stop(_params.timers.backoff_timer); - _lora_time.stop(_params.timers.ack_timeout_timer); - memset(_params.tx_buffer, 0, sizeof _params.tx_buffer); - _params.tx_buffer_len = 0; - reset_ongoing_tx(true); - tr_debug("Sending Cancelled"); - return LORAWAN_STATUS_OK; - } else { - // Event is already being dispatched so it cannot be cancelled - return LORAWAN_STATUS_BUSY; - } -} - -lorawan_status_t LoRaMac::schedule_tx() -{ - channel_selection_params_t next_channel; - lorawan_time_t backoff_time = 0; - lorawan_time_t aggregated_timeoff = 0; - uint8_t channel = 0; - uint8_t fopts_len = 0; - - if (_params.sys_params.max_duty_cycle == 255) { - return LORAWAN_STATUS_DEVICE_OFF; - } - - if (_params.sys_params.max_duty_cycle == 0) { - _params.timers.aggregated_timeoff = 0; - } - - if (MBED_CONF_LORA_DUTY_CYCLE_ON && _lora_phy->verify_duty_cycle(true)) { - _params.is_dutycycle_on = true; - } else { - _params.is_dutycycle_on = false; - } - - calculate_backOff(_params.last_channel_idx); - - next_channel.aggregate_timeoff = _params.timers.aggregated_timeoff; - next_channel.current_datarate = _params.sys_params.channel_data_rate; - next_channel.dc_enabled = _params.is_dutycycle_on; - next_channel.joined = _is_nwk_joined; - next_channel.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; - - lorawan_status_t status = _lora_phy->set_next_channel(&next_channel, - &channel, - &backoff_time, - &aggregated_timeoff); - - _params.channel = channel; - _params.timers.aggregated_timeoff = aggregated_timeoff; - - switch (status) { - case LORAWAN_STATUS_NO_CHANNEL_FOUND: - case LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND: - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - return status; - case LORAWAN_STATUS_DUTYCYCLE_RESTRICTED: - if (backoff_time != 0) { - tr_debug("DC enforced: Transmitting in %lu ms", backoff_time); - _can_cancel_tx = true; - _lora_time.start(_params.timers.backoff_timer, backoff_time); - } - return LORAWAN_STATUS_OK; - default: - break; - } - - uint8_t rx1_dr = _lora_phy->apply_DR_offset(_params.sys_params.channel_data_rate, - _params.sys_params.rx1_dr_offset); - - tr_debug("TX: Channel=%d, TX DR=%d, RX1 DR=%d", - _params.channel, _params.sys_params.channel_data_rate, rx1_dr); - - - _lora_phy->compute_rx_win_params(rx1_dr, MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, - MBED_CONF_LORA_MAX_SYS_RX_ERROR, - &_params.rx_window1_config); - - _lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate, - MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, - MBED_CONF_LORA_MAX_SYS_RX_ERROR, - &_params.rx_window2_config); - - if (!_is_nwk_joined) { - _params.rx_window1_delay = _params.sys_params.join_accept_delay1 - + _params.rx_window1_config.window_offset; - _params.rx_window2_delay = _params.sys_params.join_accept_delay2 - + _params.rx_window2_config.window_offset; - } else { - - // if the outgoing message is a proprietary message, it doesn't include any - // standard message formatting except port and MHDR. - if (_ongoing_tx_msg.type == MCPS_PROPRIETARY) { - fopts_len = 0; - } else { - fopts_len = _mac_commands.get_mac_cmd_length() + _mac_commands.get_repeat_commands_length(); - } - - // A check was performed for validity of FRMPayload in ::prepare_ongoing_tx() API. - // However, owing to the asynch nature of the send() API, we should check the - // validity again, as datarate may have changed since we last attempted to transmit. - if (validate_payload_length(_ongoing_tx_msg.f_buffer_size, - _params.sys_params.channel_data_rate, - fopts_len) == false) { - tr_error("Allowed FRMPayload = %d, FRMPayload = %d, MAC commands pending = %d", - _lora_phy->get_max_payload(_params.sys_params.channel_data_rate, - _params.is_repeater_supported), - _ongoing_tx_msg.f_buffer_size, fopts_len); - return LORAWAN_STATUS_LENGTH_ERROR; - } - _params.rx_window1_delay = _params.sys_params.recv_delay1 - + _params.rx_window1_config.window_offset; - _params.rx_window2_delay = _params.sys_params.recv_delay2 - + _params.rx_window2_config.window_offset; - } - - // handle the ack to the server here so that if the sending was cancelled - // by the user in the backoff period, we would still ack the previous frame. - if (_params.is_srv_ack_requested) { - _params.is_srv_ack_requested = false; - } - - _can_cancel_tx = false; - return send_frame_on_channel(_params.channel); -} - -void LoRaMac::calculate_backOff(uint8_t channel) -{ - lorawan_time_t elapsed_time = _lora_time.get_elapsed_time(_params.timers.mac_init_time); - _lora_phy->calculate_backoff(_is_nwk_joined, _params.is_last_tx_join_request, _params.is_dutycycle_on, - channel, elapsed_time, _params.timers.tx_toa); - - // Update aggregated time-off. This must be an assignment and no incremental - // update as we do only calculate the time-off based on the last transmission - _params.timers.aggregated_timeoff = (_params.timers.tx_toa * _params.sys_params.aggregated_duty_cycle - - _params.timers.tx_toa); -} - -void LoRaMac::reset_mac_parameters(void) -{ - _is_nwk_joined = false; - - _params.ul_frame_counter = 0; - _params.dl_frame_counter = 0; - _params.adr_ack_counter = 0; - - _params.ul_nb_rep_counter = 0; - - _params.max_ack_timeout_retries = 1; - _params.ack_timeout_retry_counter = 1; - _params.is_ack_retry_timeout_expired = false; - - _params.sys_params.max_duty_cycle = 0; - _params.sys_params.aggregated_duty_cycle = 1; - - _mac_commands.clear_command_buffer(); - _mac_commands.clear_repeat_buffer(); - - _params.is_rx_window_enabled = true; - - _lora_phy->reset_to_default_values(&_params, false); - - _params.is_node_ack_requested = false; - _params.is_srv_ack_requested = false; - - multicast_params_t *cur = _params.multicast_channels; - while (cur != NULL) { - cur->dl_frame_counter = 0; - cur = cur->next; - } - _params.channel = 0; - _params.last_channel_idx = _params.channel; - - _demod_ongoing = false; -} - -uint8_t LoRaMac::get_default_tx_datarate() -{ - return _lora_phy->get_default_tx_datarate(); -} - -void LoRaMac::enable_adaptive_datarate(bool adr_enabled) -{ - _params.sys_params.adr_on = adr_enabled; -} - -lorawan_status_t LoRaMac::set_channel_data_rate(uint8_t data_rate) -{ - if (_params.sys_params.adr_on) { - tr_error("Cannot set data rate. Please turn off ADR first."); - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - if (_lora_phy->verify_tx_datarate(data_rate, false) == true) { - _params.sys_params.channel_data_rate = data_rate; - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - return LORAWAN_STATUS_OK; -} - -bool LoRaMac::tx_ongoing() -{ - return _ongoing_tx_msg.tx_ongoing; -} - -void LoRaMac::set_tx_ongoing(bool ongoing) -{ - _can_cancel_tx = true; - _ongoing_tx_msg.tx_ongoing = ongoing; -} - -void LoRaMac::reset_ongoing_tx(bool reset_pending) -{ - _ongoing_tx_msg.tx_ongoing = false; - memset(_ongoing_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE); - _ongoing_tx_msg.f_buffer_size = 0; - if (reset_pending) { - _ongoing_tx_msg.pending_size = 0; - } -} - -int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port, - const uint8_t *const data, - uint16_t length, - uint8_t flags, - uint8_t num_retries) -{ - _ongoing_tx_msg.port = port; - uint8_t max_possible_size = 0; - uint8_t fopts_len = _mac_commands.get_mac_cmd_length() - + _mac_commands.get_repeat_commands_length(); - - // Handles unconfirmed messages - if (flags & MSG_UNCONFIRMED_FLAG) { - _ongoing_tx_msg.type = MCPS_UNCONFIRMED; - _ongoing_tx_msg.fport = port; - _ongoing_tx_msg.nb_trials = 1; - } - - // Handles confirmed messages - if (flags & MSG_CONFIRMED_FLAG) { - _ongoing_tx_msg.type = MCPS_CONFIRMED; - _ongoing_tx_msg.fport = port; - _ongoing_tx_msg.nb_trials = num_retries; - } - - // Handles proprietary messages - if (flags & MSG_PROPRIETARY_FLAG) { - _ongoing_tx_msg.type = MCPS_PROPRIETARY; - _ongoing_tx_msg.fport = port; - _ongoing_tx_msg.nb_trials = _params.sys_params.nb_trans; - // a proprietary frame only includes an MHDR field which contains MTYPE field. - // Everything else is at the discretion of the implementer - fopts_len = 0; - } - - max_possible_size = get_max_possible_tx_size(fopts_len); - - if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) { - max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE; - } - - if (max_possible_size < length) { - tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes", - length, max_possible_size); - - _ongoing_tx_msg.pending_size = length - max_possible_size; - _ongoing_tx_msg.f_buffer_size = max_possible_size; - memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size); - } else { - _ongoing_tx_msg.f_buffer_size = length; - _ongoing_tx_msg.pending_size = 0; - if (length > 0) { - memcpy(_ongoing_tx_msg.f_buffer, data, length); - } - } - - tr_info("RTS = %u bytes, PEND = %u, Port: %u", - _ongoing_tx_msg.f_buffer_size, _ongoing_tx_msg.pending_size, - _ongoing_tx_msg.fport); - - return _ongoing_tx_msg.f_buffer_size; -} - -lorawan_status_t LoRaMac::send_ongoing_tx() -{ - lorawan_status_t status; - _params.is_last_tx_join_request = false; - int8_t datarate = _params.sys_params.channel_data_rate; - - // This prohibits the data rate going below the minimum value. - datarate = MAX(datarate, (int8_t)_lora_phy->get_minimum_tx_datarate()); - - loramac_mhdr_t machdr; - machdr.value = 0; - - reset_mcps_confirmation(); - - _params.ack_timeout_retry_counter = 1; - _params.max_ack_timeout_retries = 1; - - if (MCPS_UNCONFIRMED == _ongoing_tx_msg.type) { - machdr.bits.mtype = FRAME_TYPE_DATA_UNCONFIRMED_UP; - } else if (_ongoing_tx_msg.type == MCPS_CONFIRMED) { - machdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; - _params.max_ack_timeout_retries = _ongoing_tx_msg.nb_trials; - } else if (_ongoing_tx_msg.type == MCPS_PROPRIETARY) { - machdr.bits.mtype = FRAME_TYPE_PROPRIETARY; - } else { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - if (_params.sys_params.adr_on == false) { - if (_lora_phy->verify_tx_datarate(datarate, false) == true) { - _params.sys_params.channel_data_rate = datarate; - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - } - - status = send(&machdr, _ongoing_tx_msg.fport, _ongoing_tx_msg.f_buffer, - _ongoing_tx_msg.f_buffer_size); - if (status == LORAWAN_STATUS_OK) { - _mcps_confirmation.req_type = _ongoing_tx_msg.type; - } - - return status; -} - -device_class_t LoRaMac::get_device_class() const -{ - return _device_class; -} - -void LoRaMac::set_device_class(const device_class_t &device_class, - mbed::Callbackrx2_would_be_closure_handler) -{ - _device_class = device_class; - _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) { - tr_debug("Changing device class to -> CLASS_A"); - _lora_phy->put_radio_to_sleep(); - } else if (CLASS_C == _device_class) { - _params.is_node_ack_requested = false; - _lora_phy->put_radio_to_sleep(); - _lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate, - MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, - MBED_CONF_LORA_MAX_SYS_RX_ERROR, - &_params.rx_window2_config); - } - - if (CLASS_C == _device_class) { - tr_debug("Changing device class to -> CLASS_C"); - open_rx2_window(); - } -} - -void LoRaMac::setup_link_check_request() -{ - reset_mlme_confirmation(); - - _mlme_confirmation.req_type = MLME_LINK_CHECK; - _mlme_confirmation.pending = true; - _mac_commands.add_link_check_req(); -} - -lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_otaa) -{ - if (params) { - if (is_otaa) { - if ((params->connection_u.otaa.dev_eui == NULL) - || (params->connection_u.otaa.app_eui == NULL) - || (params->connection_u.otaa.app_key == NULL) - || (params->connection_u.otaa.nb_trials == 0)) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - _params.keys.dev_eui = params->connection_u.otaa.dev_eui; - _params.keys.app_eui = params->connection_u.otaa.app_eui; - _params.keys.app_key = params->connection_u.otaa.app_key; - _params.max_join_request_trials = params->connection_u.otaa.nb_trials; - - if (!_lora_phy->verify_nb_join_trials(params->connection_u.otaa.nb_trials)) { - // Value not supported, get default - _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; - } - // Reset variable JoinRequestTrials - _params.join_request_trial_counter = 0; - - reset_mac_parameters(); - - _params.sys_params.channel_data_rate = - _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); - } else { - if ((params->connection_u.abp.dev_addr == 0) - || (params->connection_u.abp.nwk_id == 0) - || (params->connection_u.abp.nwk_skey == NULL) - || (params->connection_u.abp.app_skey == NULL)) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - _params.net_id = params->connection_u.abp.nwk_id; - _params.dev_addr = params->connection_u.abp.dev_addr; - - memcpy(_params.keys.nwk_skey, params->connection_u.abp.nwk_skey, - sizeof(_params.keys.nwk_skey)); - - memcpy(_params.keys.app_skey, params->connection_u.abp.app_skey, - sizeof(_params.keys.app_skey)); - } - } else { -#if MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION - const static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; - const static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; - const static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; - - _params.keys.app_eui = const_cast(app_eui); - _params.keys.dev_eui = const_cast(dev_eui); - _params.keys.app_key = const_cast(app_key); - _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; - - // Reset variable JoinRequestTrials - _params.join_request_trial_counter = 0; - - reset_mac_parameters(); - - _params.sys_params.channel_data_rate = - _lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); - -#else - const static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; - const static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; - - _params.net_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK) >> 25; - _params.dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; - - memcpy(_params.keys.nwk_skey, nwk_skey, sizeof(_params.keys.nwk_skey)); - - memcpy(_params.keys.app_skey, app_skey, sizeof(_params.keys.app_skey)); -#endif - } - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaMac::join(bool is_otaa) -{ - if (!is_otaa) { - set_nwk_joined(true); - return LORAWAN_STATUS_OK; - } - - reset_mlme_confirmation(); - _mlme_confirmation.req_type = MLME_JOIN; - - return send_join_request(); -} - -static void memcpy_convert_endianess(uint8_t *dst, - const uint8_t *src, - uint16_t size) -{ - dst = dst + (size - 1); - while (size--) { - *dst-- = *src++; - } -} - -lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, - loramac_frame_ctrl_t *fctrl, - const uint8_t fport, - const void *fbuffer, - uint16_t fbuffer_size) -{ - uint16_t i; - uint8_t pkt_header_len = 0; - uint32_t mic = 0; - const void *payload = fbuffer; - uint8_t frame_port = fport; - lorawan_status_t status = LORAWAN_STATUS_OK; - - _params.tx_buffer_len = 0; - - _params.is_node_ack_requested = false; - - if (fbuffer == NULL) { - fbuffer_size = 0; - } - - _params.tx_buffer_len = fbuffer_size; - - _params.tx_buffer[pkt_header_len++] = machdr->value; - - switch (machdr->bits.mtype) { - - case FRAME_TYPE_JOIN_REQ: - - _params.tx_buffer_len = pkt_header_len; - memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len, - _params.keys.app_eui, 8); - _params.tx_buffer_len += 8; - memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len, - _params.keys.dev_eui, 8); - _params.tx_buffer_len += 8; - - _params.dev_nonce = _lora_phy->get_radio_rng(); - - _params.tx_buffer[_params.tx_buffer_len++] = _params.dev_nonce & 0xFF; - _params.tx_buffer[_params.tx_buffer_len++] = (_params.dev_nonce >> 8) & 0xFF; - - if (0 != _lora_crypto.compute_join_frame_mic(_params.tx_buffer, - _params.tx_buffer_len & 0xFF, - _params.keys.app_key, - APPKEY_KEY_LENGTH, - &mic)) { - return LORAWAN_STATUS_CRYPTO_FAIL; - } - - _params.tx_buffer[_params.tx_buffer_len++] = mic & 0xFF; - _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 8) & 0xFF; - _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 16) & 0xFF; - _params.tx_buffer[_params.tx_buffer_len++] = (mic >> 24) & 0xFF; - - break; - case FRAME_TYPE_DATA_CONFIRMED_UP: - _params.is_node_ack_requested = true; - //Intentional fallthrough - case FRAME_TYPE_DATA_UNCONFIRMED_UP: { - if (!_is_nwk_joined) { - return LORAWAN_STATUS_NO_NETWORK_JOINED; - } - - if (_params.sys_params.adr_on) { - if (_lora_phy->get_next_ADR(true, - _params.sys_params.channel_data_rate, - _params.sys_params.channel_tx_power, - _params.adr_ack_counter)) { - fctrl->bits.adr_ack_req = 1; - } - } - - if (_params.is_srv_ack_requested == true) { - tr_debug("Acking to NS"); - fctrl->bits.ack = 1; - } - - _params.tx_buffer[pkt_header_len++] = (_params.dev_addr) & 0xFF; - _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 8) & 0xFF; - _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 16) & 0xFF; - _params.tx_buffer[pkt_header_len++] = (_params.dev_addr >> 24) & 0xFF; - - _params.tx_buffer[pkt_header_len++] = fctrl->value; - - _params.tx_buffer[pkt_header_len++] = _params.ul_frame_counter & 0xFF; - _params.tx_buffer[pkt_header_len++] = (_params.ul_frame_counter >> 8) - & 0xFF; - - _mac_commands.copy_repeat_commands_to_buffer(); - - const uint8_t mac_commands_len = _mac_commands.get_mac_cmd_length(); - - if ((payload != NULL) && (_params.tx_buffer_len > 0)) { - if (mac_commands_len <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH) { - fctrl->bits.fopts_len += mac_commands_len; - - // Update FCtrl field with new value of OptionsLength - _params.tx_buffer[0x05] = fctrl->value; - - const uint8_t *buffer = _mac_commands.get_mac_commands_buffer(); - for (i = 0; i < mac_commands_len; i++) { - _params.tx_buffer[pkt_header_len++] = buffer[i]; - } - } else { - _params.tx_buffer_len = mac_commands_len; - payload = _mac_commands.get_mac_commands_buffer(); - frame_port = 0; - } - } else { - if (mac_commands_len > 0) { - _params.tx_buffer_len = mac_commands_len; - payload = _mac_commands.get_mac_commands_buffer(); - frame_port = 0; - } - } - - _mac_commands.parse_mac_commands_to_repeat(); - - // We always add Port Field. Spec leaves it optional. - _params.tx_buffer[pkt_header_len++] = frame_port; - - if ((payload != NULL) && (_params.tx_buffer_len > 0)) { - - uint8_t *key = _params.keys.app_skey; - uint32_t key_length = sizeof(_params.keys.app_skey) * 8; - if (frame_port == 0) { - key = _params.keys.nwk_skey; - key_length = sizeof(_params.keys.nwk_skey) * 8; - } - if (0 != _lora_crypto.encrypt_payload((uint8_t *) payload, _params.tx_buffer_len, - key, key_length, - _params.dev_addr, UP_LINK, - _params.ul_frame_counter, - &_params.tx_buffer[pkt_header_len])) { - status = LORAWAN_STATUS_CRYPTO_FAIL; - } - } - - _params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len; - - if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len, - _params.keys.nwk_skey, sizeof(_params.keys.nwk_skey) * 8, - _params.dev_addr, - UP_LINK, _params.ul_frame_counter, &mic)) { - status = LORAWAN_STATUS_CRYPTO_FAIL; - } - - _params.tx_buffer[_params.tx_buffer_len + 0] = mic & 0xFF; - _params.tx_buffer[_params.tx_buffer_len + 1] = (mic >> 8) & 0xFF; - _params.tx_buffer[_params.tx_buffer_len + 2] = (mic >> 16) & 0xFF; - _params.tx_buffer[_params.tx_buffer_len + 3] = (mic >> 24) & 0xFF; - - _params.tx_buffer_len += LORAMAC_MFR_LEN; - } - break; - case FRAME_TYPE_PROPRIETARY: - if ((fbuffer != NULL) && (_params.tx_buffer_len > 0)) { - memcpy(_params.tx_buffer + pkt_header_len, (uint8_t *) fbuffer, - _params.tx_buffer_len); - _params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len; - } - break; - default: - status = LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - tr_debug("Frame prepared to send at port %u", frame_port); - - return status; -} - -lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) -{ - tx_config_params_t tx_config; - int8_t tx_power = 0; - - tx_config.channel = channel; - tx_config.datarate = _params.sys_params.channel_data_rate; - tx_config.tx_power = _params.sys_params.channel_tx_power; - tx_config.max_eirp = _params.sys_params.max_eirp; - tx_config.antenna_gain = _params.sys_params.antenna_gain; - tx_config.pkt_len = _params.tx_buffer_len; - - _lora_phy->tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); - - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - _mcps_confirmation.data_rate = _params.sys_params.channel_data_rate; - _mcps_confirmation.tx_power = tx_power; - _mcps_confirmation.channel = channel; - - _mcps_confirmation.tx_toa = _params.timers.tx_toa; - _mlme_confirmation.tx_toa = _params.timers.tx_toa; - - if (!_is_nwk_joined) { - _params.join_request_trial_counter++; - } - - _lora_phy->handle_send(_params.tx_buffer, _params.tx_buffer_len); - - return LORAWAN_STATUS_OK; -} - -void LoRaMac::reset_mcps_confirmation() -{ - memset((uint8_t *) &_mcps_confirmation, 0, sizeof(_mcps_confirmation)); - _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; -} - -void LoRaMac::reset_mlme_confirmation() -{ - memset((uint8_t *) &_mlme_confirmation, 0, sizeof(_mlme_confirmation)); - _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; -} - -void LoRaMac::reset_mcps_indication() -{ - memset((uint8_t *) &_mcps_indication, 0, sizeof(_mcps_indication)); - _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; -} - -lorawan_status_t LoRaMac::initialize(EventQueue *queue, - mbed::Callbackscheduling_failure_handler) -{ - _lora_time.activate_timer_subsystem(queue); - _lora_phy->initialize(&_lora_time); - - _ev_queue = queue; - _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); - - _device_class = CLASS_A; - - _params.join_request_trial_counter = 0; - _params.max_join_request_trials = 1; - _params.is_repeater_supported = false; - - _params.timers.aggregated_last_tx_time = 0; - _params.timers.aggregated_timeoff = 0; - - _lora_phy->reset_to_default_values(&_params, true); - _params.sys_params.nb_trans = 1; - - reset_mac_parameters(); - - srand(_lora_phy->get_radio_rng()); - - _params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK; - _lora_phy->setup_public_network_mode(_params.is_nwk_public); - _lora_phy->put_radio_to_sleep(); - - _lora_time.init(_params.timers.backoff_timer, - mbed::callback(this, &LoRaMac::on_backoff_timer_expiry)); - _lora_time.init(_params.timers.rx_window1_timer, - mbed::callback(this, &LoRaMac::open_rx1_window)); - _lora_time.init(_params.timers.rx_window2_timer, - mbed::callback(this, &LoRaMac::open_rx2_window)); - _lora_time.init(_params.timers.ack_timeout_timer, - mbed::callback(this, &LoRaMac::on_ack_timeout_timer_event)); - - _params.timers.mac_init_time = _lora_time.get_current_time(); - - _params.sys_params.adr_on = MBED_CONF_LORA_ADR_ON; - _params.sys_params.channel_data_rate = _lora_phy->get_default_max_tx_datarate(); - - return LORAWAN_STATUS_OK; -} - -void LoRaMac::disconnect() -{ - _lora_time.stop(_params.timers.backoff_timer); - _lora_time.stop(_params.timers.rx_window1_timer); - _lora_time.stop(_params.timers.rx_window2_timer); - _lora_time.stop(_params.timers.ack_timeout_timer); - - _lora_phy->put_radio_to_sleep(); - - _is_nwk_joined = false; - _params.is_ack_retry_timeout_expired = false; - _params.is_rx_window_enabled = true; - _params.is_node_ack_requested = false; - _params.is_srv_ack_requested = false; - - _mac_commands.clear_command_buffer(); - _mac_commands.clear_repeat_buffer(); - - reset_mcps_confirmation(); - reset_mlme_confirmation(); - reset_mcps_indication(); -} - -uint8_t LoRaMac::get_max_possible_tx_size(uint8_t fopts_len) -{ - uint8_t max_possible_payload_size = 0; - uint8_t allowed_frm_payload_size = 0; - - int8_t datarate = _params.sys_params.channel_data_rate; - int8_t tx_power = _params.sys_params.channel_tx_power; - uint32_t adr_ack_counter = _params.adr_ack_counter; - - if (_params.sys_params.adr_on) { - // Just query the information. We do not want to apply them into use - // at this point. - _lora_phy->get_next_ADR(false, datarate, tx_power, adr_ack_counter); - } - - allowed_frm_payload_size = _lora_phy->get_max_payload(datarate, - _params.is_repeater_supported); - - if (allowed_frm_payload_size >= fopts_len) { - max_possible_payload_size = allowed_frm_payload_size - fopts_len; - } else { - max_possible_payload_size = allowed_frm_payload_size; - _mac_commands.clear_command_buffer(); - _mac_commands.clear_repeat_buffer(); - } - - return max_possible_payload_size; -} - -bool LoRaMac::nwk_joined() -{ - return _is_nwk_joined; -} - -void LoRaMac::set_nwk_joined(bool joined) -{ - _is_nwk_joined = joined; -} - -lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t &plan) -{ - if (tx_ongoing()) { - return LORAWAN_STATUS_BUSY; - } - - return _channel_plan.set_plan(plan); -} - -lorawan_status_t LoRaMac::remove_channel_plan() -{ - if (tx_ongoing()) { - return LORAWAN_STATUS_BUSY; - } - - return _channel_plan.remove_plan(); -} - -lorawan_status_t LoRaMac::get_channel_plan(lorawan_channelplan_t &plan) -{ - return _channel_plan.get_plan(plan, _lora_phy->get_phy_channels()); -} - -lorawan_status_t LoRaMac::remove_single_channel(uint8_t id) -{ - if (tx_ongoing()) { - return LORAWAN_STATUS_BUSY; - } - - return _channel_plan.remove_single_channel(id); -} - -lorawan_status_t LoRaMac::multicast_channel_link(multicast_params_t *channel_param) -{ - if (channel_param == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - if (tx_ongoing()) { - return LORAWAN_STATUS_BUSY; - } - - channel_param->dl_frame_counter = 0; - - if (_params.multicast_channels == NULL) { - _params.multicast_channels = channel_param; - } else { - multicast_params_t *cur = _params.multicast_channels; - while (cur->next != NULL) { - cur = cur->next; - } - cur->next = channel_param; - } - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaMac::multicast_channel_unlink(multicast_params_t *channel_param) -{ - if (channel_param == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - if (tx_ongoing()) { - return LORAWAN_STATUS_BUSY; - } - - if (_params.multicast_channels != NULL) { - if (_params.multicast_channels == channel_param) { - _params.multicast_channels = channel_param->next; - } else { - multicast_params_t *cur = _params.multicast_channels; - - while (cur->next && cur->next != channel_param) { - cur = cur->next; - } - - if (cur->next) { - cur->next = channel_param->next; - } - } - channel_param->next = NULL; - } - - return LORAWAN_STATUS_OK; -} - -void LoRaMac::bind_phy(LoRaPHY &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; -} - diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h deleted file mode 100644 index 977843d..0000000 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ /dev/null @@ -1,706 +0,0 @@ -/** - * \file LoRaMac.h - * - * \brief LoRa MAC layer implementation - * - * \copyright Revised BSD License, see LICENSE.TXT file include in the project - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * \author Miguel Luis ( Semtech ) - * - * \author Gregory Cristian ( Semtech ) - * - * \author Daniel Jaeckle ( STACKFORCE ) - * - * \defgroup LORAMAC LoRa MAC layer implementation - * This module specifies the API implementation of the LoRaMAC layer. - * This is a placeholder for a detailed description of the LoRaMac - * layer and the supported features. - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#ifndef MBED_LORAWAN_MAC_H__ -#define MBED_LORAWAN_MAC_H__ - -#include "events/EventQueue.h" - -#include "lorastack/phy/LoRaPHY.h" - -#include "system/LoRaWANTimer.h" -#include "system/lorawan_data_structures.h" - -#include "LoRaMacChannelPlan.h" -#include "LoRaMacCommand.h" -#include "LoRaMacCrypto.h" -#if MBED_CONF_RTOS_PRESENT -#include "rtos/Mutex.h" -#endif - -#include "platform/ScopedLock.h" - -/** LoRaMac Class - * Implementation of LoRaWAN MAC layer - */ -class LoRaMac { - -public: - - /** - * Constructor - */ - LoRaMac(); - - /** - * Destructor - */ - ~LoRaMac(); - - /** - * @brief LoRaMAC layer initialization - * - * @details Initializes the LoRaMAC layer, - * - * - * @param queue [in] A pointer to the application provided EventQueue. - * - * @param scheduling_failure_handler A callback to inform upper layer if a deferred - * transmission (after backoff or retry) fails to schedule. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t initialize(events::EventQueue *queue, - mbed::Callbackscheduling_failure_handler); - - /** - * @brief Disconnect LoRaMac layer - * - * @details Cancels all outstanding requests and sets LoRaMac's - * internal state to idle. - */ - void disconnect(void); - - /** - * @brief nwk_joined Checks if device has joined to network - * @return True if joined to network, false otherwise - */ - bool nwk_joined(); - - /** - * @brief Adds a channel plan to the system. - * - * @details Adds a whole channel plan or a single new channel if the plan - * contains only one channel and 'plan.nb_channels' is set to 1. - * Please note that this functionality is not available in all regions. - * Information on the allowed ranges is available at the - * LoRaWAN Regional Parameters V1.0.2rB. - * - * @param plan [in] A reference to application provided channel plan. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t add_channel_plan(const lorawan_channelplan_t &plan); - - /** - * @brief Removes a channel plan from the system. - * - * @details Removes the whole active channel plan except the 'Default Channels'. - * Please note that this functionality is not available in all regions. - * Information on the allowed ranges is available at the - * LoRaWAN Regional Parameters V1.0.2rB. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t remove_channel_plan(); - - /** - * @brief Access active channel plan. - * - * @details Provides access to the current active channel plan. - * - * @param plan [out] A reference to application provided channel plan data - * structure which will be filled in with active channel - * plan. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t get_channel_plan(lorawan_channelplan_t &plan); - - /** - * @brief Remove a given channel from the active plan. - * - * @details Deactivates the given channel. - * - * @param id Id of the channel. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t remove_single_channel(uint8_t id); - - /** - * @brief LoRaMAC multicast channel link service. - * - * @details Links a multicast channel into the linked list. - * - * @param [in] channel_param The multicast channel parameters to link. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t multicast_channel_link(multicast_params_t *channel_param); - - /** - * @brief LoRaMAC multicast channel unlink service. - * - * @details Unlinks a multicast channel from the linked list. - * - * @param [in] channel_param The multicast channel parameters to unlink. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t multicast_channel_unlink(multicast_params_t *channel_param); - - /** Binds phy layer to MAC. - * - * @param phy LoRaPHY object - */ - void bind_phy(LoRaPHY &phy); - - /** - * @brief Schedules the frame for sending. - * - * @details Prepares a full MAC frame and schedules it for physical - * transmission. - * - * @param [in] mac_hdr MAC frame header field - * @param [in] fport Payload port - * @param [in] fbuffer MAC frame data buffer to be sent - * @param [in] fbuffer_size MAC frame data buffer size - * - * @return status Status of the operation. LORAWAN_STATUS_OK in case - * of success and a negative error code in case of - * failure. - */ - lorawan_status_t send(loramac_mhdr_t *mac_hdr, const uint8_t fport, - const void *fbuffer, uint16_t fbuffer_size); - - /** - * @brief get_default_tx_datarate Gets the default TX datarate - * @return default TX datarate. - */ - uint8_t get_default_tx_datarate(); - - /** - * @brief enable_adaptive_datarate Enables or disables adaptive datarate. - * @param adr_enabled Flag indicating is adr enabled or disabled. - */ - void enable_adaptive_datarate(bool adr_enabled); - - /** Sets up the data rate. - * - * `set_datarate()` first verifies whether the data rate given is valid or not. - * If it is valid, the system sets the given data rate to the channel. - * - * @param data_rate The intended data rate, for example DR_0 or DR_1. - * Note that the macro DR_* can mean different - * things in different regions. - * - * @return LORAWAN_STATUS_OK if everything goes well, otherwise - * a negative error code. - */ - lorawan_status_t set_channel_data_rate(uint8_t data_rate); - - /** - * @brief tx_ongoing Check whether a prepare is done or not. - * @return True if prepare_ongoing_tx is called, false otherwise. - */ - bool tx_ongoing(); - - /** - * @brief set_tx_ongoing Changes the ongoing status for prepared message. - * @param ongoing The value indicating the status. - */ - void set_tx_ongoing(bool ongoing); - - /** - * @brief reset_ongoing_tx Resets _ongoing_tx_msg. - * @param reset_pending If true resets pending size also. - */ - void reset_ongoing_tx(bool reset_pending = false); - - /** - * @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg. - * @param port The application port number. - * - * @param data A pointer to the data being sent. The ownership of the - * buffer is not transferred. - * - * @param length The size of data in bytes. - * - * @param flags A flag used to determine what type of - * message is being sent. - * - * @param num_retries Number of retries for a confirmed type message - * - * @return The number of bytes prepared for sending. - */ - int16_t prepare_ongoing_tx(const uint8_t port, const uint8_t *data, - uint16_t length, uint8_t flags, uint8_t num_retries); - - /** - * @brief send_ongoing_tx Sends the ongoing_tx_msg - * @return LORAWAN_STATUS_OK or a negative error code on failure. - */ - lorawan_status_t send_ongoing_tx(void); - - /** - * @brief device_class Returns active device class - * @return Device class in use. - */ - device_class_t get_device_class() const; - - /** - * @brief set_device_class Sets active device class. - * @param device_class Device class to use. - * @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, - mbed::Callbackrx2_would_be_closure_handler); - - /** - * @brief setup_link_check_request Adds link check request command - * to be put on next outgoing message (when it fits) - */ - void setup_link_check_request(); - - /** - * @brief prepare_join prepares arguments to be ready for join() call. - * @param params Join parameters to use, if NULL, the default will be used. - * @param is_otaa True if joining is to be done using OTAA, false for ABP. - * - * @return LORAWAN_STATUS_OK or a negative error code on failure. - */ - lorawan_status_t prepare_join(const lorawan_connect_t *params, bool is_otaa); - - /** - * @brief join Joins the network. - * @param is_otaa True if joining is to be done using OTAA, false for ABP. - * @return LORAWAN_STATUS_OK or a negative error code on failure. - */ - lorawan_status_t join(bool is_otaa); - - /** - * MAC operations upon successful transmission - */ - void on_radio_tx_done(lorawan_time_t timestamp); - - /** - * MAC operations upon reception - */ - void on_radio_rx_done(const uint8_t *const payload, uint16_t size, - int16_t rssi, int8_t snr); - - /** - * MAC operations upon transmission timeout - */ - void on_radio_tx_timeout(void); - - /** - * MAC operations upon empty reception slots - * - * @param is_timeout false when radio encountered an error - * true when the an RX slot went empty - * - * @return current RX slot - */ - void on_radio_rx_timeout(bool is_timeout); - - /** - * Handles retransmissions of Join requests if an Accept - * was not received. - * - * @returns true if a retry will be made - */ - bool continue_joining_process(void); - - /** - * Checks if the CONFIRMED data can be sent again or not. - */ - bool continue_sending_process(void); - - /** - * Read-only access to MAC primitive blocks - */ - const loramac_mcps_confirm_t *get_mcps_confirmation() const; - const loramac_mcps_indication_t *get_mcps_indication() const; - const loramac_mlme_confirm_t *get_mlme_confirmation() const; - const loramac_mlme_indication_t *get_mlme_indication() const; - - /** - * Post processing steps in response to actions carried out - * by controller layer and Mac - */ - void post_process_mcps_req(void); - void post_process_mcps_ind(void); - void post_process_mlme_request(void); - void post_process_mlme_ind(void); - - /** - * Set battery level query callback - */ - void set_batterylevel_callback(mbed::Callback battery_level); - - /** - * Returns the event ID of backoff timer. - */ - int get_backoff_timer_event_id(void); - - /** - * Clears out the TX pipe by discarding any outgoing message if the backoff - * timer is still running. - */ - lorawan_status_t clear_tx_pipe(void); - - /** - * Gets the current time - */ - lorawan_time_t get_current_time(void); - - /** - * Gets the current receive slot - */ - 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 - * the stack thread safe. - */ -#if MBED_CONF_RTOS_PRESENT - void lock(void) - { - _mutex.lock(); - } - void unlock(void) - { - _mutex.unlock(); - } -#else - void lock(void) { } - void unlock(void) { } -#endif - -private: - /** - * @brief Queries the LoRaMAC the maximum possible FRMPayload size to send. - * The LoRaMAC takes the scheduled MAC commands into account and returns - * corresponding value. - * - * @param fopts_len [in] Number of mac commands in the queue pending. - * - * @return Size of the biggest packet that can be sent. - * Please note that if the size of the MAC commands in the queue do - * not fit into the payload size on the related datarate, the LoRaMAC will - * omit the MAC commands. - */ - uint8_t get_max_possible_tx_size(uint8_t fopts_len); - - /** - * @brief set_nwk_joined This is used for ABP mode for which real joining does not happen - * @param joined True if device has joined in network, false otherwise - */ - void set_nwk_joined(bool joined); - - /** - * @brief Configures the events to trigger an MLME-Indication with - * a MLME type of MLME_SCHEDULE_UPLINK. - */ - void set_mlme_schedule_ul_indication(void); - - /** - * @brief Resets MAC specific parameters to default - */ - void reset_mac_parameters(void); - - /** - * Handles a Join Accept frame - */ - void handle_join_accept_frame(const uint8_t *payload, uint16_t size); - - /** - * Handles data frames - */ - void handle_data_frame(const uint8_t *payload, uint16_t size, uint8_t ptr_pos, - uint8_t msg_type, int16_t rssi, int8_t snr); - - /** - * Send a Join Request - */ - lorawan_status_t send_join_request(); - - /** - * Handles retransmissions - */ - lorawan_status_t handle_retransmission(); - - /** - * Checks if the frame is valid - */ - void check_frame_size(uint16_t size); - - /** - * Performs MIC - */ - bool message_integrity_check(const uint8_t *payload, uint16_t size, - uint8_t *ptr_pos, uint32_t address, - uint32_t *downlink_counter, const uint8_t *nwk_skey); - - /** - * Decrypts and extracts data and MAC commands from the received encrypted - * payload - */ - void extract_data_and_mac_commands(const uint8_t *payload, uint16_t size, - uint8_t fopts_len, uint8_t *nwk_skey, - uint8_t *app_skey, uint32_t address, - uint32_t downlink_frame_counter, - int16_t rssi, int8_t snr); - /** - * Decrypts and extracts MAC commands from the received encrypted - * payload if there is no data - */ - void extract_mac_commands_only(const uint8_t *payload, int8_t snr, uint8_t fopts_len); - - /** - * Callback function to be executed when the DC backoff timer expires - */ - void on_backoff_timer_expiry(void); - - /** - * At the end of an RX1 window timer, an RX1 window is opened using this method. - */ - void open_rx1_window(void); - - /** - * At the end of an RX2 window timer, an RX2 window is opened using this method. - */ - void open_rx2_window(void); - - /** - * A method to retry a CONFIRMED message after a particular time period - * (ACK_TIMEOUT = TIME_IN_MS) if the ack was not received - */ - void on_ack_timeout_timer_event(void); - - /*! - * \brief Check if the OnAckTimeoutTimer has do be disabled. If so, the - * function disables it. - * - * \param [in] node_ack_requested Set to true, if the node has requested an ACK - * \param [in] dev_class The device class - * \param [in] ack_received Set to true, if the node has received an ACK - * \param [in] ack_timeout_retries_counter Retries counter for confirmed uplinks - * \param [in] ack_timeout_retries Maximum retries for confirmed uplinks - */ - void check_to_disable_ack_timeout(bool node_ack_requested, - device_class_t dev_class, - bool ack_received, - uint8_t ack_timeout_retries_counter, - uint8_t ack_timeout_retries); - - /** - * Validates if the payload fits into the frame, taking the datarate - * into account. - * - * Please Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0.2 - */ - bool validate_payload_length(uint16_t length, int8_t datarate, uint8_t fopts_len); - - /** - * Prepares MAC frame on the behest of send() API. - */ - lorawan_status_t prepare_frame(loramac_mhdr_t *mac_hdr, - loramac_frame_ctrl_t *fctrl, const uint8_t fport, - const void *fbuffer, uint16_t fbuffer_size); - - /** - * Schedules a transmission on the behest of send() API. - */ - lorawan_status_t schedule_tx(); - - /** - * Calculates the back-off time for the band of a channel. - * Takes in the last used channel id as a parameter. - */ - void calculate_backOff(uint8_t channel_id); - - /** - * Hands over the MAC frame to PHY layer. - */ - lorawan_status_t send_frame_on_channel(uint8_t channel); - - /** - * Resets MAC primitive blocks - */ - void reset_mcps_confirmation(void); - void reset_mlme_confirmation(void); - void reset_mcps_indication(void); - - /** - * @brief set_tx_continuous_wave Puts the system in continuous transmission mode - * @param [in] channel A Channel to use - * @param [in] datarate A datarate to use - * @param [in] tx_power A RF output power to use - * @param [in] max_eirp A maximum possible EIRP to use - * @param [in] antenna_gain Antenna gain to use - * @param [in] timeout Time in seconds while the radio is kept in continuous wave mode - */ - void set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, - float max_eirp, float antenna_gain, uint16_t timeout); - -private: - typedef mbed::ScopedLock Lock; -#if MBED_CONF_RTOS_PRESENT - rtos::Mutex _mutex; -#endif - - /** - * Timer subsystem handle - */ - LoRaWANTimeHandler _lora_time; - - /** - * LoRa PHY layer object storage - */ - LoRaPHY *_lora_phy; - - /** - * MAC command handle - */ - LoRaMacCommand _mac_commands; - - /** - * Channel planning subsystem - */ - LoRaMacChannelPlan _channel_plan; - - /** - * Crypto handling subsystem - */ - LoRaMacCrypto _lora_crypto; - - /** - * Central MAC layer data storage - */ - loramac_protocol_params _params; - - /** - * EventQueue object storage - */ - events::EventQueue *_ev_queue; - - /** - * Class C doesn't timeout in RX2 window as it is a continuous window. - * We use this callback to inform the LoRaWANStack controller that we did - * 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 _rx2_would_be_closure_for_class_c; - - /** - * Transmission is async, i.e., a call to schedule_tx() may be deferred to - * a time after a certain back off. We use this callback to inform the - * controller layer that a specific TX transaction failed to schedule after - * backoff or retry. - */ - mbed::Callback _scheduling_failure_handler; - - timer_event_t _rx2_closure_timer_for_class_c; - - /** - * Structure to hold MCPS indication data. - */ - loramac_mcps_indication_t _mcps_indication; - - /** - * Structure to hold MCPS confirm data. - */ - loramac_mcps_confirm_t _mcps_confirmation; - - /** - * Structure to hold MLME indication data. - */ - loramac_mlme_indication_t _mlme_indication; - - /** - * Structure to hold MLME confirm data. - */ - loramac_mlme_confirm_t _mlme_confirmation; - - loramac_tx_message_t _ongoing_tx_msg; - - bool _is_nwk_joined; - - bool _can_cancel_tx; - - bool _continuous_rx2_window_open; - - device_class_t _device_class; - - uint8_t _prev_qos_level; - - bool _demod_ongoing; -}; - -#endif // MBED_LORAWAN_MAC_H__ diff --git a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp deleted file mode 100644 index a19bdf7..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRaWAN stack layer that controls both MAC and PHY underneath - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#include "LoRaMacChannelPlan.h" - -LoRaMacChannelPlan::LoRaMacChannelPlan() : _lora_phy(NULL) -{ -} - -LoRaMacChannelPlan::~LoRaMacChannelPlan() -{ -} - -void LoRaMacChannelPlan::activate_channelplan_subsystem(LoRaPHY *phy) -{ - _lora_phy = phy; -} - -lorawan_status_t LoRaMacChannelPlan::set_plan(const lorawan_channelplan_t &plan) -{ - lorawan_status_t status; - - uint8_t max_num_channels; - - if (!_lora_phy->is_custom_channel_plan_supported()) { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - max_num_channels = _lora_phy->get_max_nb_channels(); - - // check if user is setting more channels than supported - if (plan.nb_channels > max_num_channels) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - for (uint8_t i = 0; i < plan.nb_channels; i++) { - status = _lora_phy->add_channel(&plan.channels[i].ch_param, plan.channels[i].id); - - if (status != LORAWAN_STATUS_OK) { - return status; - } - } - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaMacChannelPlan::get_plan(lorawan_channelplan_t &plan, - const channel_params_t *channel_list) -{ - uint8_t max_num_channels; - uint16_t *channel_mask; - uint8_t count = 0; - - if (!_lora_phy->is_custom_channel_plan_supported()) { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - max_num_channels = _lora_phy->get_max_nb_channels(); - - channel_mask = _lora_phy->get_channel_mask(false); - - for (uint8_t i = 0; i < max_num_channels; i++) { - // skip the channels which are not enabled - if (_lora_phy->mask_bit_test(channel_mask, i) == 0) { - continue; - } - - // otherwise add them to the channel_plan struct - plan.channels[count].id = i; - plan.channels[count].ch_param.frequency = channel_list[i].frequency; - plan.channels[count].ch_param.dr_range.value = channel_list[i].dr_range.value; - plan.channels[count].ch_param.dr_range.fields.min = channel_list[i].dr_range.fields.min; - plan.channels[count].ch_param.dr_range.fields.max = channel_list[i].dr_range.fields.max; - plan.channels[count].ch_param.band = channel_list[i].band; - plan.channels[count].ch_param.rx1_frequency = channel_list[i].rx1_frequency; - count++; - } - - plan.nb_channels = count; - - return LORAWAN_STATUS_OK; -} - -lorawan_status_t LoRaMacChannelPlan::remove_plan() -{ - lorawan_status_t status = LORAWAN_STATUS_OK; - - uint8_t max_num_channels; - uint16_t *channel_mask; - uint16_t *default_channel_mask; - - if (!_lora_phy->is_custom_channel_plan_supported()) { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - max_num_channels = _lora_phy->get_max_nb_channels(); - - channel_mask = _lora_phy->get_channel_mask(false); - - default_channel_mask = _lora_phy->get_channel_mask(true); - - for (uint8_t i = 0; i < max_num_channels; i++) { - // skip any default channels - if (_lora_phy->mask_bit_test(default_channel_mask, i) != 0) { - continue; - } - - // skip any channels which are not currently enabled - if (_lora_phy->mask_bit_test(channel_mask, i) == 0) { - continue; - } - - status = remove_single_channel(i); - - if (status != LORAWAN_STATUS_OK) { - return status; - } - } - - return status; -} - -lorawan_status_t LoRaMacChannelPlan::remove_single_channel(uint8_t channel_id) -{ - uint8_t max_num_channels; - - if (!_lora_phy->is_custom_channel_plan_supported()) { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - max_num_channels = _lora_phy->get_max_nb_channels(); - - // According to specification channel IDs start from 0 and last valid - // channel ID is N-1 where N=MAX_NUM_CHANNELS. - // So any ID which is larger or equal to the Max number of channels is invalid - if (channel_id >= max_num_channels) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - if (_lora_phy->remove_channel(channel_id) == false) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - _lora_phy->put_radio_to_sleep(); - - return LORAWAN_STATUS_OK; -} - diff --git a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h deleted file mode 100644 index 6fd3a44..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - \code - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== -\endcode - -Description: LoRaWAN stack layer that controls both MAC and PHY underneath - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#ifndef MBED_LORAWAN_LORAMACCHANNELPLAN_H_ -#define MBED_LORAWAN_LORAMACCHANNELPLAN_H_ - -#include "system/lorawan_data_structures.h" -#include "lorastack/phy/LoRaPHY.h" - -class LoRaMacChannelPlan { - -public: - - /** Constructor - * - * Sets local handles to NULL. These handles will be set when the subsystem - * is activated by the MAC layer. - */ - LoRaMacChannelPlan(); - - /** Destructor - * - * Does nothing - */ - ~LoRaMacChannelPlan(); - - /** Activates Channel Planning subsystem - * - * Stores pointers to PHY layer MIB subsystem - * - * @param phy pointer to PHY layer - */ - void activate_channelplan_subsystem(LoRaPHY *phy); - - /** Set a given channel plan - * - * Used to set application provided channel plan. This API can be used to - * set a single channel as well to the existing channel plan. - * - * @param plan a reference to application channel plan. PHY layer takes a - * copy of the channel parameters provided within. - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t set_plan(const lorawan_channelplan_t &plan); - - /** Access the active channel plan - * - * Used to get active channel plan. - * - * @param plan a reference to application provided channel plan structure - * which gets filled in with active channel plan data. - * - * @param channel_list pointer to structure containing channel information - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t get_plan(lorawan_channelplan_t &plan, const channel_params_t *channel_list); - - /** Remove the active channel plan - * - * Drops the whole channel list except the 'Default Channels' ofcourse. - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t remove_plan(); - - /** Remove a single channel from the plan - * - * @param id the channel id which needs to be removed - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t remove_single_channel(uint8_t id); - -private: - - /** - * Local handles - */ - LoRaPHY *_lora_phy; -}; - - - -#endif /* MBED_LORAWAN_LORAMACCHANNELPLAN_H_ */ diff --git a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp b/features/lorawan/lorastack/mac/LoRaMacCommand.cpp deleted file mode 100644 index 0438655..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRa MAC layer implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#include -#include "LoRaMacCommand.h" -#include "LoRaMac.h" - -#include "mbed-trace/mbed_trace.h" -#define TRACE_GROUP "LMACC" - -/** - * LoRaMAC max EIRP (dBm) table. - */ -static const uint8_t max_eirp_table[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; - -LoRaMacCommand::LoRaMacCommand() -{ - sticky_mac_cmd = false; - mac_cmd_buf_idx = 0; - mac_cmd_buf_idx_to_repeat = 0; - - memset(mac_cmd_buffer, 0, sizeof(mac_cmd_buffer)); - memset(mac_cmd_buffer_to_repeat, 0, sizeof(mac_cmd_buffer_to_repeat)); -} - -void LoRaMacCommand::clear_command_buffer() -{ - mac_cmd_buf_idx = 0; -} - -uint8_t LoRaMacCommand::get_mac_cmd_length() const -{ - return mac_cmd_buf_idx; -} - -uint8_t *LoRaMacCommand::get_mac_commands_buffer() -{ - return mac_cmd_buffer; -} - -void LoRaMacCommand::parse_mac_commands_to_repeat() -{ - uint8_t i = 0; - uint8_t cmd_cnt = 0; - - for (i = 0; i < mac_cmd_buf_idx; i++) { - switch (mac_cmd_buffer[i]) { - // STICKY - case MOTE_MAC_DL_CHANNEL_ANS: - case MOTE_MAC_RX_PARAM_SETUP_ANS: { // 1 byte payload - mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i++]; - mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; - break; - } - case MOTE_MAC_RX_TIMING_SETUP_ANS: { // 0 byte payload - mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; - break; - } - - // NON-STICKY - case MOTE_MAC_DEV_STATUS_ANS: { // 2 bytes payload - i += 2; - break; - } - case MOTE_MAC_LINK_ADR_ANS: - case MOTE_MAC_NEW_CHANNEL_ANS: { // 1 byte payload - i++; - break; - } - case MOTE_MAC_TX_PARAM_SETUP_ANS: - case MOTE_MAC_DUTY_CYCLE_ANS: - case MOTE_MAC_LINK_CHECK_REQ: { // 0 byte payload - break; - } - default: { - MBED_ASSERT(false); - } - } - } - - mac_cmd_buf_idx_to_repeat = cmd_cnt; -} - -void LoRaMacCommand::clear_repeat_buffer() -{ - mac_cmd_buf_idx_to_repeat = 0; -} - -void LoRaMacCommand::copy_repeat_commands_to_buffer() -{ - memcpy(&mac_cmd_buffer[mac_cmd_buf_idx], mac_cmd_buffer_to_repeat, mac_cmd_buf_idx_to_repeat); - mac_cmd_buf_idx += mac_cmd_buf_idx_to_repeat; -} - -uint8_t LoRaMacCommand::get_repeat_commands_length() const -{ - return mac_cmd_buf_idx_to_repeat; -} - -void LoRaMacCommand::clear_sticky_mac_cmd() -{ - sticky_mac_cmd = false; -} - -bool LoRaMacCommand::has_sticky_mac_cmd() const -{ - return sticky_mac_cmd; -} - -lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index, - uint8_t commands_size, uint8_t snr, - loramac_mlme_confirm_t &mlme_conf, - lora_mac_system_params_t &mac_sys_params, - LoRaPHY &lora_phy) -{ - uint8_t status = 0; - lorawan_status_t ret_value = LORAWAN_STATUS_OK; - - while (mac_index < commands_size) { - // Decode Frame MAC commands - switch (payload[mac_index++]) { - case SRV_MAC_LINK_CHECK_ANS: - mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK; - mlme_conf.demod_margin = payload[mac_index++]; - mlme_conf.nb_gateways = payload[mac_index++]; - break; - case SRV_MAC_LINK_ADR_REQ: { - adr_req_params_t link_adr_req; - int8_t link_adr_dr = DR_0; - int8_t link_adr_txpower = TX_POWER_0; - uint8_t link_adr_nbtrans = 0; - uint8_t link_adr_nb_bytes_parsed = 0; - - // Fill parameter structure - link_adr_req.payload = &payload[mac_index - 1]; - link_adr_req.payload_size = commands_size - (mac_index - 1); - link_adr_req.adr_enabled = mac_sys_params.adr_on; - link_adr_req.ul_dwell_time = mac_sys_params.uplink_dwell_time; - link_adr_req.current_datarate = mac_sys_params.channel_data_rate; - link_adr_req.current_tx_power = mac_sys_params.channel_tx_power; - link_adr_req.current_nb_trans = mac_sys_params.nb_trans; - - // Process the ADR requests - status = lora_phy.link_ADR_request(&link_adr_req, - &link_adr_dr, - &link_adr_txpower, - &link_adr_nbtrans, - &link_adr_nb_bytes_parsed); - - // If nothing was consumed, we have a malformed packet at our hand - // we bin everything and return. link_adr_nb_bytes_parsed being 0 is - // a magic identifier letting us know that there are payload inconsistencies - if (link_adr_nb_bytes_parsed == 0) { - return LORAWAN_STATUS_UNSUPPORTED; - } - - if ((status & 0x07) == 0x07) { - mac_sys_params.channel_data_rate = link_adr_dr; - mac_sys_params.channel_tx_power = link_adr_txpower; - mac_sys_params.nb_trans = link_adr_nbtrans; - } - - // Add the answers to the buffer - for (uint8_t i = 0; i < (link_adr_nb_bytes_parsed / 5); i++) { - ret_value = add_link_adr_ans(status); - } - // Update MAC index - mac_index += link_adr_nb_bytes_parsed - 1; - } - break; - case SRV_MAC_DUTY_CYCLE_REQ: - mac_sys_params.max_duty_cycle = payload[mac_index++]; - mac_sys_params.aggregated_duty_cycle = 1 << mac_sys_params.max_duty_cycle; - ret_value = add_duty_cycle_ans(); - break; - case SRV_MAC_RX_PARAM_SETUP_REQ: { - rx_param_setup_req_t rxParamSetupReq; - - rxParamSetupReq.dr_offset = (payload[mac_index] >> 4) & 0x07; - rxParamSetupReq.datarate = payload[mac_index++] & 0x0F; - - rxParamSetupReq.frequency = (uint32_t) payload[mac_index++]; - rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 8; - rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 16; - rxParamSetupReq.frequency *= 100; - - // Perform request on region - status = lora_phy.accept_rx_param_setup_req(&rxParamSetupReq); - - if ((status & 0x07) == 0x07) { - mac_sys_params.rx2_channel.datarate = rxParamSetupReq.datarate; - mac_sys_params.rx2_channel.frequency = rxParamSetupReq.frequency; - mac_sys_params.rx1_dr_offset = rxParamSetupReq.dr_offset; - } - ret_value = add_rx_param_setup_ans(status); - } - break; - case SRV_MAC_DEV_STATUS_REQ: { - uint8_t battery_level = BAT_LEVEL_NO_MEASURE; - if (_battery_level_cb) { - battery_level = _battery_level_cb(); - } - ret_value = add_dev_status_ans(battery_level, snr & 0x3F); - break; - } - case SRV_MAC_NEW_CHANNEL_REQ: { - channel_params_t chParam; - int8_t channel_id = payload[mac_index++]; - - chParam.frequency = (uint32_t) payload[mac_index++]; - chParam.frequency |= (uint32_t) payload[mac_index++] << 8; - chParam.frequency |= (uint32_t) payload[mac_index++] << 16; - chParam.frequency *= 100; - chParam.rx1_frequency = 0; - chParam.dr_range.value = payload[mac_index++]; - - status = lora_phy.request_new_channel(channel_id, &chParam); - - ret_value = add_new_channel_ans(status); - } - break; - case SRV_MAC_RX_TIMING_SETUP_REQ: { - uint8_t delay = payload[mac_index++] & 0x0F; - - if (delay == 0) { - delay++; - } - mac_sys_params.recv_delay1 = delay * 1000; - mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; - ret_value = add_rx_timing_setup_ans(); - } - break; - case SRV_MAC_TX_PARAM_SETUP_REQ: { - uint8_t eirpDwellTime = payload[mac_index++]; - uint8_t ul_dwell_time; - uint8_t dl_dwell_time; - uint8_t max_eirp; - - ul_dwell_time = 0; - dl_dwell_time = 0; - - if ((eirpDwellTime & 0x20) == 0x20) { - dl_dwell_time = 1; - } - if ((eirpDwellTime & 0x10) == 0x10) { - ul_dwell_time = 1; - } - max_eirp = eirpDwellTime & 0x0F; - - // Check the status for correctness - if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { - // Accept command - mac_sys_params.uplink_dwell_time = ul_dwell_time; - mac_sys_params.downlink_dwell_time = dl_dwell_time; - mac_sys_params.max_eirp = max_eirp_table[max_eirp]; - // Add command response - ret_value = add_tx_param_setup_ans(); - } - } - break; - case SRV_MAC_DL_CHANNEL_REQ: { - uint8_t channel_id = payload[mac_index++]; - uint32_t rx1_frequency; - - rx1_frequency = (uint32_t) payload[mac_index++]; - rx1_frequency |= (uint32_t) payload[mac_index++] << 8; - rx1_frequency |= (uint32_t) payload[mac_index++] << 16; - rx1_frequency *= 100; - status = lora_phy.dl_channel_request(channel_id, rx1_frequency); - - ret_value = add_dl_channel_ans(status); - } - break; - default: - // Unknown command. ABORT MAC commands processing - tr_error("Invalid MAC command (0x%X)!", payload[mac_index]); - return LORAWAN_STATUS_UNSUPPORTED; - } - } - return ret_value; -} - -int32_t LoRaMacCommand::cmd_buffer_remaining() const -{ - // The maximum buffer length must take MAC commands to re-send into account. - return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; -} - -void LoRaMacCommand::set_batterylevel_callback(mbed::Callback battery_level) -{ - _battery_level_cb = battery_level; -} - -lorawan_status_t LoRaMacCommand::add_link_check_req() -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 0) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_CHECK_REQ; - // No payload for this command - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status) -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 1) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_ADR_ANS; - mac_cmd_buffer[mac_cmd_buf_idx++] = status; - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_duty_cycle_ans() -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 0) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DUTY_CYCLE_ANS; - // No payload for this answer - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_rx_param_setup_ans(uint8_t status) -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 1) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_PARAM_SETUP_ANS; - // Status: Datarate ACK, Channel ACK - mac_cmd_buffer[mac_cmd_buf_idx++] = status; - // This is a sticky MAC command answer. Setup indication - sticky_mac_cmd = true; - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_dev_status_ans(uint8_t battery, uint8_t margin) -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 2) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEV_STATUS_ANS; - // 1st byte Battery - // 2nd byte Margin - mac_cmd_buffer[mac_cmd_buf_idx++] = battery; - mac_cmd_buffer[mac_cmd_buf_idx++] = margin; - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_new_channel_ans(uint8_t status) -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 1) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_NEW_CHANNEL_ANS; - // Status: Datarate range OK, Channel frequency OK - mac_cmd_buffer[mac_cmd_buf_idx++] = status; - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_rx_timing_setup_ans() -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 0) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_TIMING_SETUP_ANS; - // No payload for this answer - // This is a sticky MAC command answer. Setup indication - sticky_mac_cmd = true; - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_tx_param_setup_ans() -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 0) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_TX_PARAM_SETUP_ANS; - // No payload for this answer - ret = LORAWAN_STATUS_OK; - } - return ret; -} - -lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status) -{ - lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; - if (cmd_buffer_remaining() > 1) { - mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DL_CHANNEL_ANS; - // Status: Uplink frequency exists, Channel frequency OK - mac_cmd_buffer[mac_cmd_buf_idx++] = status; - // This is a sticky MAC command answer. Setup indication - sticky_mac_cmd = true; - ret = LORAWAN_STATUS_OK; - } - return ret; -} diff --git a/features/lorawan/lorastack/mac/LoRaMacCommand.h b/features/lorawan/lorastack/mac/LoRaMacCommand.h deleted file mode 100644 index 93f285e..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacCommand.h +++ /dev/null @@ -1,253 +0,0 @@ -/** - * \file LoRaMacCommand.h - * - * \brief LoRa MAC layer implementation - * - * \copyright Revised BSD License, see LICENSE.TXT file include in the project - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * \author Miguel Luis ( Semtech ) - * - * \author Gregory Cristian ( Semtech ) - * - * \author Daniel Jaeckle ( STACKFORCE ) - * - * \defgroup LORAMAC LoRa MAC layer implementation - * This module specifies the API implementation of the LoRaMAC layer. - * This is a placeholder for a detailed description of the LoRaMac - * layer and the supported features. - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#ifndef __LORAMACCOMMAND_H__ -#define __LORAMACCOMMAND_H__ - -#include -#include "system/lorawan_data_structures.h" -#include "lorastack/phy/LoRaPHY.h" - -/*! - * Maximum MAC commands buffer size - */ -#define LORA_MAC_COMMAND_MAX_LENGTH 128 - -class LoRaMac; - -/** LoRaMacCommand Class - * Helper class for LoRaMac layer to handle any MAC commands - */ -class LoRaMacCommand { - -public: - LoRaMacCommand(); - - /** - * @brief Clear MAC command buffer. - */ - void clear_command_buffer(void); - - /** - * @brief Get the length of MAC commands - * - * @return status Length of used MAC buffer (bytes) - */ - uint8_t get_mac_cmd_length() const; - - /** - * @brief Get MAC command buffer - * - * @return Pointer to MAC command buffer - */ - uint8_t *get_mac_commands_buffer(); - - /** - * @brief Parses the MAC commands which must be re-sent. - */ - void parse_mac_commands_to_repeat(); - - /** - * @brief Clear MAC command repeat buffer. - */ - void clear_repeat_buffer(); - - /** - * @brief Copy MAC commands from repeat buffer to actual MAC command buffer. - */ - void copy_repeat_commands_to_buffer(); - - /** - * @brief Get the length of MAC commands in repeat buffer - * - * @return status Length of used MAC Repeat buffer (bytes) - */ - uint8_t get_repeat_commands_length() const; - - /** - * @brief Clear sticky MAC commands. - */ - void clear_sticky_mac_cmd(); - - /** - * @brief Check if MAC command buffer contains sticky commands - * - * @return status True: buffer has sticky MAC commands in it, false: no sticky commands in buffer - */ - bool has_sticky_mac_cmd() const; - - /** - * @brief Decodes MAC commands in the fOpts field and in the payload - * - * @return status Function status. LORAWAN_STATUS_OK if command successful. - */ - lorawan_status_t process_mac_commands(const uint8_t *payload, uint8_t mac_index, - uint8_t commands_size, uint8_t snr, - loramac_mlme_confirm_t &mlme_conf, - lora_mac_system_params_t &mac_params, - LoRaPHY &lora_phy); - - /** - * @brief Adds a new LinkCheckReq MAC command to be sent. - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_link_check_req(); - - /** - * @brief Set battery level query callback method - * If callback is not set, BAT_LEVEL_NO_MEASURE is returned. - */ - void set_batterylevel_callback(mbed::Callback battery_level); - -private: - /** - * @brief Get the remaining size of the MAC command buffer - * - * @return Remaining free space in buffer (bytes). - */ - int32_t cmd_buffer_remaining() const; - - /** - * @brief Adds a new LinkAdrAns MAC command to be sent. - * - * @param [in] status Status bits - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_link_adr_ans(uint8_t status); - - /** - * @brief Adds a new DutyCycleAns MAC command to be sent. - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_duty_cycle_ans(); - - /** - * @brief Adds a new RXParamSetupAns MAC command to be sent. - * - * @param [in] status Status bits - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_rx_param_setup_ans(uint8_t status); - - /** - * @brief Adds a new DevStatusAns MAC command to be sent. - * - * @param [in] battery Battery level - * @param [in] margin Demodulation signal-to-noise ratio (dB) - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_dev_status_ans(uint8_t battery, uint8_t margin); - - /** - * @brief Adds a new NewChannelAns MAC command to be sent. - * - * @param [in] status Status bits - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_new_channel_ans(uint8_t status); - - /** - * @brief Adds a new RXTimingSetupAns MAC command to be sent. - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_rx_timing_setup_ans(); - - /** - * @brief Adds a new TXParamSetupAns MAC command to be sent. - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_tx_param_setup_ans(); - - /** - * @brief Adds a new DlChannelAns MAC command to be sent. - * - * @param [in] status Status bits - * - * @return status Function status: LORAWAN_STATUS_OK: OK, - * LORAWAN_STATUS_LENGTH_ERROR: Buffer full - */ - lorawan_status_t add_dl_channel_ans(uint8_t status); - -private: - /** - * Indicates if there are any pending sticky MAC commands - */ - bool sticky_mac_cmd; - - /** - * Contains the current Mac command buffer index in 'mac_cmd_buffer' - */ - uint8_t mac_cmd_buf_idx; - - /** - * Contains the current Mac command buffer index for MAC commands to repeat in - * 'mac_cmd_buffer_to_repeat' - */ - uint8_t mac_cmd_buf_idx_to_repeat; - - /** - * Buffer containing the MAC layer commands - */ - uint8_t mac_cmd_buffer[LORA_MAC_COMMAND_MAX_LENGTH]; - - /** - * Buffer containing the MAC layer commands which must be repeated - */ - uint8_t mac_cmd_buffer_to_repeat[LORA_MAC_COMMAND_MAX_LENGTH]; - - mbed::Callback _battery_level_cb; -}; - -#endif //__LORAMACCOMMAND_H__ diff --git a/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp b/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp deleted file mode 100644 index cb0a419..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * Description: LoRa MAC crypto implementation - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) - * - * - * Copyright (c) 2017, Arm Limited and affiliates. - * - * SPDX-License-Identifier: BSD-3-Clause -*/ - -#include -#include -#include - -#include "LoRaMacCrypto.h" -#include "system/lorawan_data_structures.h" -#include "mbedtls/platform.h" - - -#if defined(MBEDTLS_CMAC_C) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_CIPHER_C) - -LoRaMacCrypto::LoRaMacCrypto() -{ -#if defined(MBEDTLS_PLATFORM_C) - int ret = mbedtls_platform_setup(NULL); - if (ret != 0) { - MBED_ASSERT(0 && "LoRaMacCrypto: Fail in mbedtls_platform_setup."); - } -#endif /* MBEDTLS_PLATFORM_C */ -} - -LoRaMacCrypto::~LoRaMacCrypto() -{ -#if defined(MBEDTLS_PLATFORM_C) - mbedtls_platform_teardown(NULL); -#endif /* MBEDTLS_PLATFORM_C */ -} - -int LoRaMacCrypto::compute_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, const uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint32_t *mic) -{ - uint8_t computed_mic[16] = {}; - uint8_t mic_block_b0[16] = {}; - int ret = 0; - - mic_block_b0[0] = 0x49; - - mic_block_b0[5] = dir; - - mic_block_b0[6] = (address) & 0xFF; - mic_block_b0[7] = (address >> 8) & 0xFF; - mic_block_b0[8] = (address >> 16) & 0xFF; - mic_block_b0[9] = (address >> 24) & 0xFF; - - mic_block_b0[10] = (seq_counter) & 0xFF; - mic_block_b0[11] = (seq_counter >> 8) & 0xFF; - mic_block_b0[12] = (seq_counter >> 16) & 0xFF; - mic_block_b0[13] = (seq_counter >> 24) & 0xFF; - - mic_block_b0[15] = size & 0xFF; - - mbedtls_cipher_init(aes_cmac_ctx); - - const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); - - if (NULL != cipher_info) { - ret = mbedtls_cipher_setup(aes_cmac_ctx, cipher_info); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, mic_block_b0, sizeof(mic_block_b0)); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, buffer, size & 0xFF); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_finish(aes_cmac_ctx, computed_mic); - if (0 != ret) { - goto exit; - } - - *mic = (uint32_t)((uint32_t) computed_mic[3] << 24 - | (uint32_t) computed_mic[2] << 16 - | (uint32_t) computed_mic[1] << 8 | (uint32_t) computed_mic[0]); - } else { - ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED; - } - -exit: - mbedtls_cipher_free(aes_cmac_ctx); - return ret; -} - -int LoRaMacCrypto::encrypt_payload(const uint8_t *buffer, uint16_t size, - const uint8_t *key, const uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *enc_buffer) -{ - uint16_t i; - uint8_t bufferIndex = 0; - uint16_t ctr = 1; - int ret = 0; - uint8_t a_block[16] = {}; - uint8_t s_block[16] = {}; - - mbedtls_aes_init(&aes_ctx); - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); - if (0 != ret) { - goto exit; - } - - a_block[0] = 0x01; - a_block[5] = dir; - - a_block[6] = (address) & 0xFF; - a_block[7] = (address >> 8) & 0xFF; - a_block[8] = (address >> 16) & 0xFF; - a_block[9] = (address >> 24) & 0xFF; - - a_block[10] = (seq_counter) & 0xFF; - a_block[11] = (seq_counter >> 8) & 0xFF; - a_block[12] = (seq_counter >> 16) & 0xFF; - a_block[13] = (seq_counter >> 24) & 0xFF; - - while (size >= 16) { - a_block[15] = ((ctr) & 0xFF); - ctr++; - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, a_block, - s_block); - if (0 != ret) { - goto exit; - } - - for (i = 0; i < 16; i++) { - enc_buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ s_block[i]; - } - size -= 16; - bufferIndex += 16; - } - - if (size > 0) { - a_block[15] = ((ctr) & 0xFF); - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, a_block, - s_block); - if (0 != ret) { - goto exit; - } - - for (i = 0; i < size; i++) { - enc_buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ s_block[i]; - } - } - -exit: - mbedtls_aes_free(&aes_ctx); - return ret; -} - -int LoRaMacCrypto::decrypt_payload(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *dec_buffer) -{ - return encrypt_payload(buffer, size, key, key_length, address, dir, seq_counter, - dec_buffer); -} - -int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t *mic) -{ - uint8_t computed_mic[16] = {}; - int ret = 0; - - mbedtls_cipher_init(aes_cmac_ctx); - const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); - - if (NULL != cipher_info) { - ret = mbedtls_cipher_setup(aes_cmac_ctx, cipher_info); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, buffer, size & 0xFF); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_cipher_cmac_finish(aes_cmac_ctx, computed_mic); - if (0 != ret) { - goto exit; - } - - *mic = (uint32_t)((uint32_t) computed_mic[3] << 24 - | (uint32_t) computed_mic[2] << 16 - | (uint32_t) computed_mic[1] << 8 | (uint32_t) computed_mic[0]); - } else { - ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED; - } - -exit: - mbedtls_cipher_free(aes_cmac_ctx); - return ret; -} - -int LoRaMacCrypto::decrypt_join_frame(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint8_t *dec_buffer) -{ - int ret = 0; - - mbedtls_aes_init(&aes_ctx); - - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); - if (0 != ret) { - goto exit; - } - - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, buffer, - dec_buffer); - if (0 != ret) { - goto exit; - } - - // Check if optional CFList is included - if (size >= 16) { - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, buffer + 16, - dec_buffer + 16); - } - -exit: - mbedtls_aes_free(&aes_ctx); - return ret; -} - -int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, - const uint8_t *app_nonce, uint16_t dev_nonce, - uint8_t *nwk_skey, uint8_t *app_skey) -{ - uint8_t nonce[16]; - uint8_t *p_dev_nonce = (uint8_t *) &dev_nonce; - int ret = 0; - - mbedtls_aes_init(&aes_ctx); - - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); - if (0 != ret) { - goto exit; - } - - memset(nonce, 0, sizeof(nonce)); - nonce[0] = 0x01; - memcpy(nonce + 1, app_nonce, 6); - memcpy(nonce + 7, p_dev_nonce, 2); - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, nwk_skey); - if (0 != ret) { - goto exit; - } - - memset(nonce, 0, sizeof(nonce)); - nonce[0] = 0x02; - memcpy(nonce + 1, app_nonce, 6); - memcpy(nonce + 7, p_dev_nonce, 2); - ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, app_skey); - -exit: - mbedtls_aes_free(&aes_ctx); - return ret; -} -#else - -LoRaMacCrypto::LoRaMacCrypto() -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); -} - -LoRaMacCrypto::~LoRaMacCrypto() -{ -} - -// If mbedTLS is not configured properly, these dummies will ensure that -// user knows what is wrong and in addition to that these ensure that -// Mbed-OS compiles properly under normal conditions where LoRaWAN in conjunction -// with mbedTLS is not being used. -int LoRaMacCrypto::compute_mic(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, - uint8_t dir, uint32_t, uint32_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -int LoRaMacCrypto::encrypt_payload(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, - uint8_t, uint32_t, uint8_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -int LoRaMacCrypto::decrypt_payload(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t, - uint8_t, uint32_t, uint8_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -int LoRaMacCrypto::decrypt_join_frame(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint8_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *, uint32_t, const uint8_t *, uint16_t, - uint8_t *, uint8_t *) -{ - MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); - - // Never actually reaches here - return LORAWAN_STATUS_CRYPTO_FAIL; -} - -#endif diff --git a/features/lorawan/lorastack/mac/LoRaMacCrypto.h b/features/lorawan/lorastack/mac/LoRaMacCrypto.h deleted file mode 100644 index 7117367..0000000 --- a/features/lorawan/lorastack/mac/LoRaMacCrypto.h +++ /dev/null @@ -1,165 +0,0 @@ -/** -\code - - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -\endcode - -Description: LoRa MAC Crypto implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#ifndef MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ -#define MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ - -#include "mbedtls/aes.h" -#include "mbedtls/cmac.h" - - -class LoRaMacCrypto { -public: - /** - * Constructor - */ - LoRaMacCrypto(); - - /** - * Destructor - */ - ~LoRaMacCrypto(); - - /** - * Computes the LoRaMAC frame MIC field - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] mic - Computed MIC field - * - * @return 0 if successful, or a cipher specific error code - */ - int compute_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint32_t *mic); - - /** - * Performs payload encryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] enc_buffer - Encrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ - int encrypt_payload(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *enc_buffer); - - /** - * Performs payload decryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] dec_buffer - Decrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ - int decrypt_payload(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *dec_buffer); - - /** - * Computes the LoRaMAC Join Request frame MIC field - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [out] mic - Computed MIC field - * - * @return 0 if successful, or a cipher specific error code - * - */ - int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint32_t *mic); - - /** - * Computes the LoRaMAC join frame decryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [out] dec_buffer - Decrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ - int decrypt_join_frame(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t key_length, - uint8_t *dec_buffer); - - /** - * Computes the LoRaMAC join frame decryption - * - * @param [in] key - AES key to be used - * @param [in] key_length - Length of the key (bits) - * @param [in] app_nonce - Application nonce - * @param [in] dev_nonce - Device nonce - * @param [out] nwk_skey - Network session key - * @param [out] app_skey - Application session key - * - * @return 0 if successful, or a cipher specific error code - */ - int compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, - const uint8_t *app_nonce, uint16_t dev_nonce, - uint8_t *nwk_skey, uint8_t *app_skey); - -private: - /** - * AES computation context variable - */ - mbedtls_aes_context aes_ctx; - - /** - * CMAC computation context variable - */ - mbedtls_cipher_context_t aes_cmac_ctx[1]; -}; - -#endif // MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp deleted file mode 100644 index 3161e65..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ /dev/null @@ -1,1464 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#include -#include -#include -#include -#include - -#include "LoRaPHY.h" - -#define BACKOFF_DC_1_HOUR 100 -#define BACKOFF_DC_10_HOURS 1000 -#define BACKOFF_DC_24_HOURS 10000 -#define MAX_PREAMBLE_LENGTH 8.0f -#define TICK_GRANULARITY_JITTER 1.0f -#define CHANNELS_IN_MASK 16 - -LoRaPHY::LoRaPHY() - : _radio(NULL), - _lora_time(NULL) -{ - memset(&phy_params, 0, sizeof(phy_params)); -} - -LoRaPHY::~LoRaPHY() -{ - _radio = NULL; -} - -void LoRaPHY::initialize(LoRaWANTimeHandler *lora_time) -{ - _lora_time = lora_time; -} - -bool LoRaPHY::mask_bit_test(const uint16_t *mask, unsigned bit) -{ - return mask[bit / 16] & (1U << (bit % 16)); -} - -void LoRaPHY::mask_bit_set(uint16_t *mask, unsigned bit) -{ - mask[bit / 16] |= (1U << (bit % 16)); -} - -void LoRaPHY::mask_bit_clear(uint16_t *mask, unsigned bit) -{ - mask[bit / 16] &= ~(1U << (bit % 16)); -} - -void LoRaPHY::set_radio_instance(LoRaRadio &radio) -{ - _radio = &radio; -} - -void LoRaPHY::put_radio_to_sleep() -{ - _radio->lock(); - _radio->sleep(); - _radio->unlock(); -} - -void LoRaPHY::put_radio_to_standby() -{ - _radio->lock(); - _radio->standby(); - _radio->unlock(); -} - -void LoRaPHY::setup_public_network_mode(bool set) -{ - _radio->lock(); - _radio->set_public_network(set); - _radio->unlock(); -} - -void LoRaPHY::handle_receive(void) -{ - _radio->lock(); - _radio->receive(); - _radio->unlock(); -} - -// For DevNonce for example -uint32_t LoRaPHY::get_radio_rng() -{ - uint32_t rand; - - _radio->lock(); - rand = _radio->random(); - _radio->unlock(); - - return rand; -} - -void LoRaPHY::handle_send(uint8_t *buf, uint8_t size) -{ - _radio->lock(); - _radio->send(buf, size); - _radio->unlock(); -} - -uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t *new_channel) -{ - if (!phy_params.custom_channelplans_supported) { - return 0; - } - - uint8_t status = 0x03; - - if (new_channel->frequency == 0) { - // Remove - if (remove_channel(channel_id) == false) { - status &= 0xFC; - } - } else { - new_channel->band = lookup_band_for_frequency(new_channel->frequency); - switch (add_channel(new_channel, channel_id)) { - case LORAWAN_STATUS_OK: { - break; - } - case LORAWAN_STATUS_FREQUENCY_INVALID: { - status &= 0xFE; - break; - } - case LORAWAN_STATUS_DATARATE_INVALID: { - status &= 0xFD; - break; - } - case LORAWAN_STATUS_FREQ_AND_DR_INVALID: { - status &= 0xFC; - break; - } - default: { - status &= 0xFC; - break; - } - } - } - - return status; -} - -int32_t LoRaPHY::get_random(int32_t min, int32_t max) -{ - return (int32_t) rand() % (max - min + 1) + min; -} - -bool LoRaPHY::verify_channel_DR(uint16_t *channel_mask, int8_t dr) -{ - 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, (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; - } - } - } - - return false; -} - -bool LoRaPHY::val_in_range(int8_t value, int8_t min, int8_t max) -{ - if ((value >= min) && (value <= max)) { - return true; - } - - return false; -} - -bool LoRaPHY::disable_channel(uint16_t *channel_mask, uint8_t id, - uint8_t max_channels_num) -{ - uint8_t index = id / 16; - - if ((index > phy_params.channels.mask_size) || (id >= max_channels_num)) { - return false; - } - - // Deactivate channel - mask_bit_clear(channel_mask, id); - - return true; -} - -uint8_t LoRaPHY::count_bits(uint16_t mask, uint8_t nbBits) -{ - uint8_t nbActiveBits = 0; - - for (uint8_t j = 0; j < nbBits; j++) { - if (mask_bit_test(&mask, j)) { - nbActiveBits++; - } - } - - return nbActiveBits; -} - -uint8_t LoRaPHY::num_active_channels(uint16_t *channel_mask, uint8_t start_idx, - uint8_t stop_idx) -{ - uint8_t nb_channels = 0; - - if (channel_mask == NULL) { - return 0; - } - - for (uint8_t i = start_idx; i < stop_idx; i++) { - nb_channels += count_bits(channel_mask[i], 16); - } - - return nb_channels; -} - -void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t len) -{ - if ((dest_mask != NULL) && (src_mask != NULL)) { - for (uint8_t i = 0; i < len; i++) { - dest_mask[i] = src_mask[i]; - } - } -} - -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; - channel_params_t *channel_list = phy_params.channels.channel_list; - - if (joined == true) { - band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; - return; - } - - band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; - band_table[channel_list[channel].band].last_join_tx_time = last_tx_done_time; - -} - -lorawan_time_t LoRaPHY::update_band_timeoff(bool joined, bool duty_cycle, - band_t *bands, uint8_t nb_bands) -{ - lorawan_time_t next_tx_delay = (lorawan_time_t)(-1); - - // Update bands Time OFF - for (uint8_t i = 0; i < nb_bands; i++) { - if (MBED_CONF_LORA_DUTY_CYCLE_ON_JOIN && joined == false) { - uint32_t txDoneTime = MAX(_lora_time->get_elapsed_time(bands[i].last_join_tx_time), - (duty_cycle == true) ? - _lora_time->get_elapsed_time(bands[i].last_tx_time) : 0); - - if (bands[i].off_time <= txDoneTime) { - bands[i].off_time = 0; - } - - if (bands[i].off_time != 0) { - next_tx_delay = MIN(bands[i].off_time - txDoneTime, next_tx_delay); - // add a random delay from 200ms to a 1000ms - next_tx_delay += (rand() % 800 + 200); - } - } else { - // if network has been joined - if (duty_cycle == true) { - - if (bands[i].off_time <= _lora_time->get_elapsed_time(bands[i].last_tx_time)) { - bands[i].off_time = 0; - } - - if (bands[i].off_time != 0) { - next_tx_delay = MIN(bands[i].off_time - _lora_time->get_elapsed_time(bands[i].last_tx_time), - next_tx_delay); - } - } else { - // if duty cycle is not on - next_tx_delay = 0; - bands[i].off_time = 0; - } - } - } - - return next_tx_delay; -} - -uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t *payload, - uint8_t payload_size, - link_adr_params_t *params) -{ - uint8_t ret_index = 0; - - if (payload_size >= 5) { - - // Parse datarate and tx power - params->datarate = payload[1]; - params->tx_power = params->datarate & 0x0F; - params->datarate = (params->datarate >> 4) & 0x0F; - - // Parse ChMask - params->channel_mask = (uint16_t) payload[2]; - params->channel_mask |= (uint16_t) payload[3] << 8; - - // Parse ChMaskCtrl and nbRep - params->nb_rep = payload[4]; - params->ch_mask_ctrl = (params->nb_rep >> 4) & 0x07; - params->nb_rep &= 0x0F; - - // LinkAdrReq has 4 bytes length + 1 byte CMD - ret_index = 5; - } - - return ret_index; -} - -uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params, - int8_t *dr, int8_t *tx_pow, uint8_t *nb_rep) -{ - uint8_t status = verify_params->status; - int8_t datarate = verify_params->datarate; - int8_t tx_power = verify_params->tx_power; - int8_t nb_repetitions = verify_params->nb_rep; - - // Handle the case when ADR is off. - if (verify_params->adr_enabled == false) { - // When ADR is off, we are allowed to change the channels mask and the NbRep, - // if the datarate and the TX power of the LinkAdrReq are set to 0x0F. - if ((verify_params->datarate != 0x0F) || (verify_params->tx_power != 0x0F)) { - status = 0; - nb_repetitions = verify_params->current_nb_rep; - } - - // Get the current datarate and tx power - datarate = verify_params->current_datarate; - tx_power = verify_params->current_tx_power; - } - - if (status != 0) { - // Verify channel datarate - 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) == false) { - // Verify if the maximum TX power is exceeded - if (phy_params.max_tx_power > tx_power) { - // Apply maximum TX power. Accept TX power. - tx_power = phy_params.max_tx_power; - } else { - status &= 0xFB; // TxPower KO - } - } - } - - // If the status is ok, verify the NbRep - if (status == 0x07 && nb_repetitions == 0) { - // Restore the default value according to the LoRaWAN specification - nb_repetitions = 1; - } - - // Apply changes - *dr = datarate; - *tx_pow = tx_power; - *nb_rep = nb_repetitions; - - return status; -} - -float LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth) -{ - // in milliseconds - return ((float)(1 << phy_dr) / (float) bandwidth * 1000); -} - -float LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr) -{ - return (8.0f / (float) phy_dr); // 1 symbol equals 1 byte -} - - -void LoRaPHY::get_rx_window_params(float t_symb, uint8_t min_rx_symb, - float error_fudge, float wakeup_time, - uint32_t *window_length, uint32_t *window_length_ms, - int32_t *window_offset, - uint8_t phy_dr) -{ - float target_rx_window_offset; - float window_len_in_ms; - - if (phy_params.fsk_supported && phy_dr == phy_params.max_rx_datarate) { - min_rx_symb = MAX_PREAMBLE_LENGTH; - } - - // We wish to be as close as possible to the actual start of data, i.e., - // we are interested in the preamble symbols which are at the tail of the - // preamble sequence. - target_rx_window_offset = (MAX_PREAMBLE_LENGTH - min_rx_symb) * t_symb; //in ms - - // Actual window offset in ms in response to timing error fudge factor and - // radio wakeup/turned around time. - *window_offset = floor(target_rx_window_offset - error_fudge - wakeup_time); - - // possible wait for next symbol start if we start inside the preamble - float possible_wait_for_symb_start = MIN(t_symb, - ((2 * error_fudge) + wakeup_time + TICK_GRANULARITY_JITTER)); - - // how early we might start reception relative to transmit start (so negative if before transmit starts) - float earliest_possible_start_time = *window_offset - error_fudge - TICK_GRANULARITY_JITTER; - - // time in (ms) we may have to wait for the other side to start transmission - float possible_wait_for_transmit = -earliest_possible_start_time; - - // Minimum reception time plus extra time (in ms) we may have turned on before the - // other side started transmission - window_len_in_ms = (min_rx_symb * t_symb) + MAX(possible_wait_for_transmit, possible_wait_for_symb_start); - - // Setting the window_length in terms of 'symbols' for LoRa modulation or - // in terms of 'bytes' for FSK - *window_length = (uint32_t) ceil(window_len_in_ms / t_symb); - *window_length_ms = window_len_in_ms; -} - -int8_t LoRaPHY::compute_tx_power(int8_t tx_power_idx, float max_eirp, - float antenna_gain) -{ - int8_t phy_tx_power = 0; - - phy_tx_power = (int8_t) floor((max_eirp - (tx_power_idx * 2U)) - antenna_gain); - - return phy_tx_power; -} - - -int8_t LoRaPHY::get_next_lower_dr(int8_t dr, int8_t min_dr) -{ - uint8_t next_lower_dr = dr; - - do { - if (next_lower_dr != min_dr) { - next_lower_dr -= 1; - } - } while ((next_lower_dr != min_dr) && !is_datarate_supported(next_lower_dr)); - - return next_lower_dr; -} - -uint8_t LoRaPHY::get_bandwidth(uint8_t dr) -{ - uint32_t *bandwidths = (uint32_t *) phy_params.bandwidths.table; - - switch (bandwidths[dr]) { - default: - case 125000: - return 0; - case 250000: - return 1; - case 500000: - return 2; - } -} - -uint8_t LoRaPHY::enabled_channel_count(uint8_t datarate, - const uint16_t *channel_mask, - uint8_t *channel_indices, - uint8_t *delayTx) -{ - uint8_t count = 0; - uint8_t delay_transmission = 0; - - for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) { - if (mask_bit_test(channel_mask, i)) { - - if (val_in_range(datarate, phy_params.channels.channel_list[i].dr_range.fields.min, - phy_params.channels.channel_list[i].dr_range.fields.max) == 0) { - // data rate range invalid for this channel - continue; - } - - band_t *band_table = (band_t *) phy_params.bands.table; - if (band_table[phy_params.channels.channel_list[i].band].off_time > 0) { - // Check if the band is available for transmission - delay_transmission++; - continue; - } - - // otherwise count the channel as enabled - channel_indices[count++] = i; - } - } - - *delayTx = delay_transmission; - - return count; -} - -bool LoRaPHY::is_datarate_supported(const int8_t datarate) const -{ - if (datarate < phy_params.datarates.size) { - return (((uint8_t *)phy_params.datarates.table)[datarate] != 0) ? true : false; - } else { - return false; - } -} - -void LoRaPHY::reset_to_default_values(loramac_protocol_params *params, bool init) -{ - if (init) { - params->is_dutycycle_on = phy_params.duty_cycle_enabled; - - params->sys_params.max_rx_win_time = phy_params.max_rx_window; - - params->sys_params.recv_delay1 = phy_params.recv_delay1; - - params->sys_params.recv_delay2 = phy_params.recv_delay2; - - params->sys_params.join_accept_delay1 = phy_params.join_accept_delay1; - - params->sys_params.join_accept_delay2 = phy_params.join_accept_delay2; - - params->sys_params.downlink_dwell_time = phy_params.dl_dwell_time_setting; - } - - params->sys_params.channel_tx_power = get_default_tx_power(); - - // We shall always start with highest achievable data rate. - // Subsequent decrease in data rate will mean increase in range henceforth. - params->sys_params.channel_data_rate = get_default_max_tx_datarate(); - - params->sys_params.rx1_dr_offset = phy_params.default_rx1_dr_offset; - - params->sys_params.rx2_channel.frequency = get_default_rx2_frequency(); - - params->sys_params.rx2_channel.datarate = get_default_rx2_datarate(); - - params->sys_params.uplink_dwell_time = phy_params.ul_dwell_time_setting; - - params->sys_params.max_eirp = phy_params.default_max_eirp; - - params->sys_params.antenna_gain = phy_params.default_antenna_gain; -} - -int8_t LoRaPHY::get_next_lower_tx_datarate(int8_t datarate) -{ - if (phy_params.ul_dwell_time_setting == 0) { - return get_next_lower_dr(datarate, phy_params.min_tx_datarate); - } - - return get_next_lower_dr(datarate, phy_params.dwell_limit_datarate); - -} - -uint8_t LoRaPHY::get_minimum_rx_datarate() -{ - if (phy_params.dl_dwell_time_setting == 0) { - return phy_params.min_rx_datarate; - } - return phy_params.dwell_limit_datarate; -} - -uint8_t LoRaPHY::get_minimum_tx_datarate() -{ - if (phy_params.ul_dwell_time_setting == 0) { - return phy_params.min_tx_datarate; - } - return phy_params.dwell_limit_datarate; -} - -uint8_t LoRaPHY::get_default_tx_datarate() -{ - return phy_params.default_datarate; -} - -uint8_t LoRaPHY::get_default_max_tx_datarate() -{ - return phy_params.default_max_datarate; -} - -uint8_t LoRaPHY::get_default_tx_power() -{ - return phy_params.default_tx_power; -} - -uint8_t LoRaPHY::get_max_payload(uint8_t datarate, bool use_repeater) -{ - uint8_t *payload_table = NULL; - - if (use_repeater) { -// if (datarate >= phy_params.payloads_with_repeater.size) { -// //TODO: Can this ever happen? If yes, should we return 0? -// } - payload_table = (uint8_t *) phy_params.payloads_with_repeater.table; - } else { - payload_table = (uint8_t *) phy_params.payloads.table; - } - - return payload_table[datarate]; -} - -uint16_t LoRaPHY::get_maximum_frame_counter_gap() -{ - return phy_params.max_fcnt_gap; -} - -uint32_t LoRaPHY::get_ack_timeout() -{ - uint16_t ack_timeout_rnd = phy_params.ack_timeout_rnd; - return (phy_params.ack_timeout + get_random(0, ack_timeout_rnd)); -} - -uint32_t LoRaPHY::get_default_rx2_frequency() -{ - return phy_params.rx_window2_frequency; -} - -uint8_t LoRaPHY::get_default_rx2_datarate() -{ - return phy_params.rx_window2_datarate; -} - -uint16_t *LoRaPHY::get_channel_mask(bool get_default) -{ - if (get_default) { - return phy_params.channels.default_mask; - } - return phy_params.channels.mask; -} - -uint8_t LoRaPHY::get_max_nb_channels() -{ - return phy_params.max_channel_cnt; -} - -channel_params_t *LoRaPHY::get_phy_channels() -{ - return phy_params.channels.channel_list; -} - -bool LoRaPHY::is_custom_channel_plan_supported() -{ - return phy_params.custom_channelplans_supported; -} - -void LoRaPHY::restore_default_channels() -{ - // Restore channels default mask - for (uint8_t i = 0; i < phy_params.channels.mask_size; i++) { - phy_params.channels.mask[i] |= phy_params.channels.default_mask[i]; - } -} - -bool LoRaPHY::verify_rx_datarate(uint8_t datarate) -{ - if (is_datarate_supported(datarate)) { - if (phy_params.dl_dwell_time_setting == 0) { - //TODO: Check this! datarate must be same as minimum! Can be compared directly if OK - return val_in_range(datarate, - phy_params.min_rx_datarate, - phy_params.max_rx_datarate); - } else { - return val_in_range(datarate, - phy_params.dwell_limit_datarate, - phy_params.max_rx_datarate); - } - } - return false; -} - -bool LoRaPHY::verify_tx_datarate(uint8_t datarate, bool use_default) -{ - if (!is_datarate_supported(datarate)) { - return false; - } - - if (use_default) { - return val_in_range(datarate, phy_params.default_datarate, - phy_params.default_max_datarate); - } else if (phy_params.ul_dwell_time_setting == 0) { - return val_in_range(datarate, phy_params.min_tx_datarate, - phy_params.max_tx_datarate); - } else { - return val_in_range(datarate, phy_params.dwell_limit_datarate, - phy_params.max_tx_datarate); - } -} - -bool LoRaPHY::verify_tx_power(uint8_t tx_power) -{ - return val_in_range(tx_power, phy_params.max_tx_power, - phy_params.min_tx_power); -} - -bool LoRaPHY::verify_duty_cycle(bool cycle) -{ - if (cycle == phy_params.duty_cycle_enabled) { - return true; - } - return false; -} - -bool LoRaPHY::verify_nb_join_trials(uint8_t nb_join_trials) -{ - if (nb_join_trials < MBED_CONF_LORA_NB_TRIALS) { - return false; - } - return true; -} - -void LoRaPHY::apply_cf_list(const uint8_t *payload, uint8_t size) -{ - // if the underlying PHY doesn't support CF-List, ignore the request - if (!phy_params.cflist_supported) { - return; - } - - channel_params_t new_channel; - - // Setup default datarate range - new_channel.dr_range.value = (phy_params.default_max_datarate << 4) | - phy_params.default_datarate; - - // Size of the optional CF list - if (size != 16) { - return; - } - - // Last byte is RFU, don't take it into account - // NOTE: Currently the PHY layers supported by LoRaWAN who accept a CF-List - // define first 2 or 3 channels as default channels. this function is - // written keeping that in mind. If there would be a PHY in the future that - // accepts CF-list but have haphazard allocation of default channels, we - // should override this function in the implementation of that particular - // PHY. - for (uint8_t i = 0, channel_id = phy_params.default_channel_cnt; - channel_id < phy_params.max_channel_cnt; i += 3, channel_id++) { - if (channel_id < (phy_params.cflist_channel_cnt + phy_params.default_channel_cnt)) { - // Channel frequency - new_channel.frequency = (uint32_t) payload[i]; - new_channel.frequency |= ((uint32_t) payload[i + 1] << 8); - new_channel.frequency |= ((uint32_t) payload[i + 2] << 16); - new_channel.frequency *= 100; - - // Initialize alternative frequency to 0 - new_channel.rx1_frequency = 0; - } else { - new_channel.frequency = 0; - new_channel.dr_range.value = 0; - new_channel.rx1_frequency = 0; - } - - if (new_channel.frequency != 0) { - //lookup for band - new_channel.band = lookup_band_for_frequency(new_channel.frequency); - - // Try to add channel - add_channel(&new_channel, channel_id); - } else { - remove_channel(channel_id); - } - } -} - - -bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t &dr_out, - int8_t &tx_power_out, uint32_t &adr_ack_cnt) -{ - bool set_adr_ack_bit = false; - - uint16_t ack_limit_plus_delay = phy_params.adr_ack_limit + phy_params.adr_ack_delay; - - if (dr_out == phy_params.min_tx_datarate) { - adr_ack_cnt = 0; - return set_adr_ack_bit; - } - - if (adr_ack_cnt < phy_params.adr_ack_limit) { - return set_adr_ack_bit; - } - - // ADR ack counter is larger than ADR-ACK-LIMIT - set_adr_ack_bit = true; - tx_power_out = phy_params.max_tx_power; - - if (adr_ack_cnt >= ack_limit_plus_delay) { - if ((adr_ack_cnt % phy_params.adr_ack_delay) == 1) { - // Decrease the datarate - dr_out = get_next_lower_tx_datarate(dr_out); - - if (dr_out == phy_params.min_tx_datarate) { - // We must set adrAckReq to false as soon as we reach the lowest datarate - set_adr_ack_bit = false; - if (restore_channel_mask) { - // Re-enable default channels - restore_default_channels(); - } - } - } - } - - return set_adr_ack_bit; -} - -void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, - uint32_t rx_error, - rx_config_params_t *rx_conf_params) -{ - float t_symbol = 0.0; - - // Get the datarate, perform a boundary check - rx_conf_params->datarate = MIN(datarate, phy_params.max_rx_datarate); - - rx_conf_params->bandwidth = get_bandwidth(rx_conf_params->datarate); - - if (phy_params.fsk_supported && rx_conf_params->datarate == phy_params.max_rx_datarate) { - // FSK - t_symbol = compute_symb_timeout_fsk(((uint8_t *)phy_params.datarates.table)[rx_conf_params->datarate]); - } else { - // LoRa - t_symbol = compute_symb_timeout_lora(((uint8_t *)phy_params.datarates.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, (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME, - &rx_conf_params->window_timeout, &rx_conf_params->window_timeout_ms, - &rx_conf_params->window_offset, - rx_conf_params->datarate); -} - -uint32_t LoRaPHY::get_rx_time_on_air(uint8_t modem, uint16_t pkt_len) -{ - uint32_t toa = 0; - - _radio->lock(); - toa = _radio->time_on_air((radio_modems_t) modem, pkt_len); - _radio->unlock(); - - return toa; -} - -bool LoRaPHY::rx_config(rx_config_params_t *rx_conf) -{ - uint8_t dr = rx_conf->datarate; - uint8_t max_payload = 0; - uint8_t phy_dr = 0; - - // Read the physical datarate from the datarates table - uint8_t *datarate_table = (uint8_t *) phy_params.datarates.table; - uint8_t *payload_table = (uint8_t *) phy_params.payloads.table; - uint8_t *payload_with_repeater_table = (uint8_t *) phy_params.payloads_with_repeater.table; - - phy_dr = datarate_table[dr]; - - _radio->lock(); - - _radio->set_channel(rx_conf->frequency); - - // Radio configuration - if (dr == DR_7 && phy_params.fsk_supported) { - rx_conf->modem_type = MODEM_FSK; - _radio->set_rx_config((radio_modems_t) rx_conf->modem_type, 50000, phy_dr * 1000, 0, 83333, MAX_PREAMBLE_LENGTH, - rx_conf->window_timeout, false, 0, true, 0, 0, - false, rx_conf->is_rx_continuous); - } else { - rx_conf->modem_type = MODEM_LORA; - _radio->set_rx_config((radio_modems_t) rx_conf->modem_type, rx_conf->bandwidth, phy_dr, 1, 0, - MAX_PREAMBLE_LENGTH, - rx_conf->window_timeout, false, 0, false, 0, 0, - true, rx_conf->is_rx_continuous); - } - - if (rx_conf->is_repeater_supported) { - max_payload = payload_with_repeater_table[dr]; - } else { - max_payload = payload_table[dr]; - } - - _radio->set_max_payload_length((radio_modems_t) rx_conf->modem_type, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - _radio->unlock(); - - return true; -} - -bool LoRaPHY::tx_config(tx_config_params_t *tx_conf, int8_t *tx_power, - lorawan_time_t *tx_toa) -{ - radio_modems_t modem; - int8_t phy_dr = ((uint8_t *)phy_params.datarates.table)[tx_conf->datarate]; - channel_params_t *list = phy_params.channels.channel_list; - uint8_t band_idx = list[tx_conf->channel].band; - band_t *bands = (band_t *)phy_params.bands.table; - - // limit TX power if set to too much - tx_conf->tx_power = MAX(tx_conf->tx_power, bands[band_idx].max_tx_pwr); - - uint8_t bandwidth = get_bandwidth(tx_conf->datarate); - int8_t phy_tx_power = 0; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(tx_conf->tx_power, tx_conf->max_eirp, - tx_conf->antenna_gain); - - _radio->lock(); - - // Setup the radio frequency - _radio->set_channel(list[tx_conf->channel].frequency); - - if (tx_conf->datarate == phy_params.max_tx_datarate) { - // High Speed FSK channel - modem = MODEM_FSK; - _radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth, - phy_dr * 1000, 0, MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, - false, true, 0, 0, false, 3000); - } else { - modem = MODEM_LORA; - _radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1, - MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, - false, true, 0, 0, false, 3000); - } - - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(modem, tx_conf->pkt_len); - // Get the time-on-air of the next tx frame - *tx_toa = _radio->time_on_air(modem, tx_conf->pkt_len); - - _radio->unlock(); - - *tx_power = tx_conf->tx_power; - - return true; -} - -uint8_t LoRaPHY::link_ADR_request(adr_req_params_t *link_adr_req, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, uint8_t *nb_bytes_processed) -{ - uint8_t status = 0x07; - link_adr_params_t adr_settings; - uint8_t next_index = 0; - uint8_t bytes_processed = 0; - - // rather than dynamically allocating memory, we choose to set - // a channel mask list size of unity here as we know that all - // the PHY layer implementations who have more than 16 channels, i.e., - // have channel mask list size more than unity, override this method. - uint16_t temp_channel_mask[1] = {0}; - - verify_adr_params_t verify_params; - - while (bytes_processed < link_adr_req->payload_size && - link_adr_req->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { - // Get ADR request parameters - next_index = parse_link_ADR_req(&(link_adr_req->payload[bytes_processed]), - link_adr_req->payload_size - bytes_processed, - &adr_settings); - - if (next_index == 0) { - bytes_processed = 0; - // break loop, malformed packet - break; - } - - // Update bytes processed - bytes_processed += next_index; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - // Setup temporary channels mask - temp_channel_mask[0] = adr_settings.channel_mask; - - // Verify channels mask - if (adr_settings.ch_mask_ctrl == 0 && temp_channel_mask[0] == 0) { - status &= 0xFE; // Channel mask KO - } - - // channel mask applies to first 16 channels - if (adr_settings.ch_mask_ctrl == 0 || adr_settings.ch_mask_ctrl == 6) { - - for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) { - - // turn on all channels if channel mask control is 6 - if (adr_settings.ch_mask_ctrl == 6) { - if (phy_params.channels.channel_list[i].frequency != 0) { - mask_bit_set(temp_channel_mask, i); - } - - continue; - } - - // if channel mask control is 0, we test the bits and - // frequencies and change the status if we find a discrepancy - if ((mask_bit_test(temp_channel_mask, i)) && - (phy_params.channels.channel_list[i].frequency == 0)) { - // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - } else { - // Channel mask control applies to RFUs - status &= 0xFE; // Channel mask KO - } - } - - if (bytes_processed == 0) { - *nb_bytes_processed = 0; - return status; - } - - if (is_datarate_supported(adr_settings.datarate)) { - verify_params.status = status; - - verify_params.adr_enabled = link_adr_req->adr_enabled; - verify_params.current_datarate = link_adr_req->current_datarate; - verify_params.current_tx_power = link_adr_req->current_tx_power; - verify_params.current_nb_rep = link_adr_req->current_nb_trans; - - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; - - - verify_params.channel_mask = temp_channel_mask; - - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); - } else { - status &= 0xFD; // Datarate KO - } - - // Update channelsMask if everything is correct - if (status == 0x07) { - // Set the channels mask to a default value - memset(phy_params.channels.mask, 0, - sizeof(uint16_t)*phy_params.channels.mask_size); - - // Update the channels mask - copy_channel_mask(phy_params.channels.mask, temp_channel_mask, - phy_params.channels.mask_size); - } - - // Update status variables - *dr_out = adr_settings.datarate; - *tx_power_out = adr_settings.tx_power; - *nb_rep_out = adr_settings.nb_rep; - *nb_bytes_processed = bytes_processed; - - return status; -} - -uint8_t LoRaPHY::accept_rx_param_setup_req(rx_param_setup_req_t *params) -{ - uint8_t status = 0x07; - - if (lookup_band_for_frequency(params->frequency) < 0) { - status &= 0xFE; - } - - // Verify radio frequency - if (_radio->check_rf_frequency(params->frequency) == false) { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (val_in_range(params->datarate, phy_params.min_rx_datarate, - phy_params.max_rx_datarate) == 0) { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (val_in_range(params->dr_offset, phy_params.min_rx1_dr_offset, - phy_params.max_rx1_dr_offset) == 0) { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; -} - -bool LoRaPHY::accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time) -{ - if (phy_params.accept_tx_param_setup_req) { - phy_params.ul_dwell_time_setting = ul_dwell_time; - phy_params.dl_dwell_time_setting = dl_dwell_time; - } - - return phy_params.accept_tx_param_setup_req; -} - -int LoRaPHY::lookup_band_for_frequency(uint32_t freq) const -{ - // check all sub bands (if there are sub-bands) to check if the given - // frequency falls into any of the frequency ranges - - for (int band = 0; band < phy_params.bands.size; band++) { - if (verify_frequency_for_band(freq, band)) { - return band; - } - } - - return -1; -} - -bool LoRaPHY::verify_frequency_for_band(uint32_t freq, uint8_t band) const -{ - band_t *bands_table = (band_t *)phy_params.bands.table; - - if (freq <= bands_table[band].higher_band_freq - && freq >= bands_table[band].lower_band_freq) { - return true; - } else { - return false; - } -} - -uint8_t LoRaPHY::dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency) -{ - if (!phy_params.dl_channel_req_supported) { - return 0; - } - - uint8_t status = 0x03; - - // Verify if the frequency is supported - int band = lookup_band_for_frequency(rx1_frequency); - if (band < 0) { - status &= 0xFE; - } - - // Verify if an uplink frequency exists - if (phy_params.channels.channel_list[channel_id].frequency == 0) { - status &= 0xFD; - } - - // Apply Rx1 frequency, if the status is OK - if (status == 0x03) { - phy_params.channels.channel_list[channel_id].rx1_frequency = rx1_frequency; - } - - return status; -} - -/** - * Alternate datarate algorithm for join requests. - * - We check from the PHY and take note of total - * number of data rates available upto the default data rate for - * default channels. - * - * - Application sets a total number of re-trials for a Join Request, i.e., - * MBED_CONF_LORA_NB_TRIALS. So MAC layer will send us a counter - * nb_trials < MBED_CONF_LORA_NB_TRIALS which is the current number of trial. - * - * - We roll over total available datarates and pick one according to the - * number of trial sequentially. - * - * - We always start from the Default Data rate and and set the next lower - * data rate for every iteration. - * - * - MAC layer will stop when maximum number of re-trials, i.e., - * MBED_CONF_LORA_NB_TRIALS is achieved. - * - * So essentially MBED_CONF_LORA_NB_TRIALS should be a multiple of range of - * data rates available. For example, in EU868 band, default max. data rate is - * DR_5 and min. data rate is DR_0, so total data rates available are 6. - * - * Hence MBED_CONF_LORA_NB_TRIALS should be a multiple of 6. Setting, - * MBED_CONF_LORA_NB_TRIALS = 6 would mean that every data rate will be tried - * exactly once starting from the largest and finishing at the smallest. - * - * PHY layers which do not have datarates scheme similar to EU band will ofcourse - * override this method. - */ -int8_t LoRaPHY::get_alternate_DR(uint8_t nb_trials) -{ - int8_t datarate = 0; - uint8_t total_nb_datrates = (phy_params.default_max_datarate - phy_params.min_tx_datarate) + 1; - - uint8_t res = nb_trials % total_nb_datrates; - - if (res == 0) { - datarate = phy_params.min_tx_datarate; - } else if (res == 1) { - datarate = phy_params.default_max_datarate; - } else { - datarate = (phy_params.default_max_datarate - res) + 1; - } - - return datarate; -} - -void LoRaPHY::calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, - lorawan_time_t elapsed_time, lorawan_time_t tx_toa) -{ - band_t *band_table = (band_t *) phy_params.bands.table; - channel_params_t *channel_list = phy_params.channels.channel_list; - - uint8_t band_idx = channel_list[channel].band; - uint16_t duty_cycle = band_table[band_idx].duty_cycle; - uint16_t join_duty_cycle = 0; - - // Reset time-off to initial value. - band_table[band_idx].off_time = 0; - - if (MBED_CONF_LORA_DUTY_CYCLE_ON_JOIN && joined == false) { - // Get the join duty cycle - if (elapsed_time < 3600000) { - join_duty_cycle = BACKOFF_DC_1_HOUR; - } else if (elapsed_time < (3600000 + 36000000)) { - join_duty_cycle = BACKOFF_DC_10_HOURS; - } else { - join_duty_cycle = BACKOFF_DC_24_HOURS; - } - - // Apply the most restricting duty cycle - duty_cycle = MAX(duty_cycle, join_duty_cycle); - } - - // No back-off if the last frame was not a join request and when the - // duty cycle is not enabled - if (dc_enabled == false && last_tx_was_join_req == false) { - band_table[band_idx].off_time = 0; - } else { - // Apply band time-off. - band_table[band_idx].off_time = tx_toa * duty_cycle - tx_toa; - } -} - -lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t *params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff) -{ - uint8_t channel_count = 0; - uint8_t delay_tx = 0; - - // Note here that the PHY layer implementations which have more than - // 16 channels at their disposal, override this function. That's why - // it is safe to assume that we are dealing with a block of 16 channels - // i.e., EU like implementations. So rather than dynamically allocating - // memory we chose to use a magic number of 16 - uint8_t enabled_channels[16]; - - memset(enabled_channels, 0xFF, sizeof(uint8_t) * 16); - - lorawan_time_t next_tx_delay = 0; - band_t *band_table = (band_t *) phy_params.bands.table; - - if (num_active_channels(phy_params.channels.mask, 0, - phy_params.channels.mask_size) == 0) { - - // Reactivate default channels - copy_channel_mask(phy_params.channels.mask, - phy_params.channels.default_mask, - phy_params.channels.mask_size); - } - - if (params->aggregate_timeoff - <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeoff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(params->joined, - params->dc_enabled, - band_table, phy_params.bands.size); - - // Search how many channels are enabled - channel_count = enabled_channel_count(params->current_datarate, - phy_params.channels.mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = params->aggregate_timeoff - - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); - } - - if (channel_count > 0) { - // We found a valid channel - *channel = enabled_channels[get_random(0, channel_count - 1)]; - *time = 0; - return LORAWAN_STATUS_OK; - } - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - // Datarate not supported by any channel, restore defaults - copy_channel_mask(phy_params.channels.mask, - phy_params.channels.default_mask, - phy_params.channels.mask_size); - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; -} - -lorawan_status_t LoRaPHY::add_channel(const channel_params_t *new_channel, - uint8_t id) -{ - bool dr_invalid = false; - bool freq_invalid = false; - - if (!phy_params.custom_channelplans_supported - || id >= phy_params.max_channel_cnt) { - - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - // Validate the datarate range - if (val_in_range(new_channel->dr_range.fields.min, - phy_params.min_tx_datarate, - phy_params.max_tx_datarate) == 0) { - dr_invalid = true; - } - - if (val_in_range(new_channel->dr_range.fields.max, phy_params.min_tx_datarate, - phy_params.max_tx_datarate) == 0) { - dr_invalid = true; - } - - if (new_channel->dr_range.fields.min > new_channel->dr_range.fields.max) { - dr_invalid = true; - } - - // 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 != DR_0) { - dr_invalid = true; - } - - // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE - if (val_in_range(new_channel->dr_range.fields.max, - phy_params.default_max_datarate, - phy_params.max_tx_datarate) == 0) { - dr_invalid = true; - } - - // We are not allowed to change the frequency - if (new_channel->frequency != phy_params.channels.channel_list[id].frequency) { - freq_invalid = true; - } - } - - // Check frequency - if (!freq_invalid) { - if (new_channel->band >= phy_params.bands.size - || verify_frequency_for_band(new_channel->frequency, - new_channel->band) == false) { - freq_invalid = true; - } - } - - // Check status - if (dr_invalid && freq_invalid) { - return LORAWAN_STATUS_FREQ_AND_DR_INVALID; - } - - if (dr_invalid) { - return LORAWAN_STATUS_DATARATE_INVALID; - } - - if (freq_invalid) { - return LORAWAN_STATUS_FREQUENCY_INVALID; - } - - memmove(&(phy_params.channels.channel_list[id]), new_channel, sizeof(channel_params_t)); - - phy_params.channels.channel_list[id].band = new_channel->band; - - mask_bit_set(phy_params.channels.mask, id); - - return LORAWAN_STATUS_OK; -} - -bool LoRaPHY::remove_channel(uint8_t channel_id) -{ - // upper layers are checking if the custom channel planning is supported or - // not. So we don't need to worry about that - if (mask_bit_test(phy_params.channels.default_mask, channel_id)) { - return false; - } - - - // Remove the channel from the list of channels - const channel_params_t empty_channel = { 0, 0, {0}, 0 }; - phy_params.channels.channel_list[channel_id] = empty_channel; - - return disable_channel(phy_params.channels.mask, channel_id, - phy_params.max_channel_cnt); -} - -void LoRaPHY::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) -{ - band_t *bands_table = (band_t *) phy_params.bands.table; - channel_params_t *channels = phy_params.channels.channel_list; - - if (params->tx_power > bands_table[channels[params->channel].band].max_tx_pwr) { - params->tx_power = bands_table[channels[params->channel].band].max_tx_pwr; - } - - int8_t phy_tx_power = 0; - uint32_t frequency = 0; - - if (given_frequency == 0) { - frequency = channels[params->channel].frequency; - } else { - frequency = given_frequency; - } - - // Calculate physical TX power - if (params->max_eirp > 0 && params->antenna_gain > 0) { - phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp, - params->antenna_gain); - } else { - phy_tx_power = params->tx_power; - } - - _radio->lock(); - _radio->set_tx_continuous_wave(frequency, phy_tx_power, params->timeout); - _radio->unlock(); -} - -uint8_t LoRaPHY::apply_DR_offset(int8_t dr, int8_t dr_offset) -{ - int8_t datarate = dr - dr_offset; - - if (datarate < 0) { - datarate = phy_params.min_tx_datarate; - } - - return datarate; -} - - diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h deleted file mode 100644 index 786d0b6..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ /dev/null @@ -1,683 +0,0 @@ -/** - * @file LoRaPHY.h - * - * @brief An abstract class providing radio object to children and - * provide base for implementing LoRa PHY layer - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * Description: LoRa PHY layer - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_BASE_ -#define MBED_OS_LORAPHY_BASE_ - -#include "platform/NonCopyable.h" - -#include "system/LoRaWANTimer.h" -#include "LoRaRadio.h" -#include "lora_phy_ds.h" - -/** LoRaPHY Class - * Parent class for LoRa regional PHY implementations - */ -class LoRaPHY : private mbed::NonCopyable { - -public: - virtual ~LoRaPHY(); - - /** Initialize LoRaPHY - * - * LoRaMac calls this to initialize LoRaPHY. - * - * @param lora_time a pointer to LoRaWANTimeHandler object - */ - void initialize(LoRaWANTimeHandler *lora_time); - - /** Stores a reference to Radio object. - * - * Application is responsible for constructing a 'LoRaRadio' object - * which is passed down to the PHY layer. - * - * @param radio a reference to radio driver object - */ - void set_radio_instance(LoRaRadio &radio); - - /** Puts radio in sleep mode. - * - * Requests the radio driver to enter sleep mode. - */ - void put_radio_to_sleep(void); - - /** Puts radio in standby mode. - * - * Requests the radio driver to enter standby mode. - */ - void put_radio_to_standby(void); - - /** Puts radio in receive mode. - * - * Requests the radio driver to enter receive mode. - */ - void handle_receive(void); - - /** Delegates MAC layer request to transmit packet. - * - * @param buf a pointer to the data which needs to be transmitted - * - * @param size size of the data in bytes - */ - void handle_send(uint8_t *buf, uint8_t size); - - /** Enables/Disables public network mode. - * - * Public and private LoRaWAN network constitute different preambles and - * Net IDs. This API isused to tell the radio which network mode is in use. - * - * @param set true or false - */ - void setup_public_network_mode(bool set); - - /** Provides a random number from radio. - * - * Returns a 32-bit random unsigned integer value based upon RSSI - * measurements. - * - * @return a 32-bit long random number - * - */ - uint32_t get_radio_rng(); - - /** - * @brief calculate_backoff Calculates and applies duty cycle back-off time. - * Explicitly updates the band time-off. - * - * @param joined Set to true, if the node has already joined a network, otherwise false. - * @param last_tx_was_join_req Set to true, if the last uplink was a join request. - * @param dc_enabled Set to true, if the duty cycle is enabled, otherwise false. - * @param channel The current channel index. - * @param elapsed_time Elapsed time since the start of the node. - * @param tx_toa Time-on-air of the last transmission. - */ - void calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, - lorawan_time_t elapsed_time, lorawan_time_t tx_toa); - - /** - * Tests if a channel is on or off in the channel mask - */ - bool mask_bit_test(const uint16_t *mask, unsigned bit); - - /** - * Tests if a channel is on or off in the channel mask - */ - void mask_bit_set(uint16_t *mask, unsigned bit); - - /** - * Tests if a channel is on or off in the channel mask - */ - void mask_bit_clear(uint16_t *mask, unsigned bit); - - /** Entertain a new channel request MAC command. - * - * MAC command subsystem processes the new channel request coming form - * the network server and then MAC layer asks the PHY layer to entertain - * the request. - * - * @param channel_id The channel ID. - * @param new_channel A pointer to the new channel's parameters. - * - * @return bit mask, according to the LoRaWAN spec 1.0.2. - */ - virtual uint8_t request_new_channel(int8_t channel_id, channel_params_t *new_channel); - - /** Process PHY layer state after a successful transmission. - * @brief set_last_tx_done Updates times of the last transmission for the particular channel and - * band upon which last transmission took place. - * @param channel The channel in use. - * @param joined Boolean telling if node has joined the network. - * @param last_tx_done_time The last TX done time. - */ - virtual void set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time); - - /** Enables default channels only. - * - * Falls back to a channel mask where only default channels are enabled, all - * other channels are disabled. - */ - virtual void restore_default_channels(); - - /** Processes the incoming CF-list. - * - * Handles the payload containing CF-list and enables channels defined - * therein. - * - * @param payload Payload to process. - * @param size Size of the payload. - * - */ - virtual void apply_cf_list(const uint8_t *payload, uint8_t size); - - /** Calculates the next datarate to set, when ADR is on or off. - * - * @param restore_channel_mask A boolean set restore channel mask in case - * of failure. - * - * @param dr_out The calculated datarate for the next TX. - * - * @param tx_power_out The TX power for the next TX. - * - * @param adr_ack_counter The calculated ADR acknowledgement counter. - * - * @return True, if an ADR request should be performed. - */ - bool get_next_ADR(bool restore_channel_mask, int8_t &dr_out, - int8_t &tx_power_out, uint32_t &adr_ack_counter); - - /** Configure radio reception. - * - * @param [in] config A pointer to the RX configuration. - * - * @return True, if the configuration was applied successfully. - */ - virtual bool rx_config(rx_config_params_t *config); - - /** Computing Receive Windows - * - * The algorithm tries to calculate the length of receive windows (i.e., - * the minimum time it should remain to acquire a lock on the Preamble - * for synchronization) and the error offset which compensates for the system - * timing errors. Basic idea behind the algorithm is to optimize for the - * reception of last 'min_rx_symbols' symbols out of transmitted Premable - * symbols. The algorithm compensates for the clock drifts, tick granularity - * and system wake up time (from sleep state) by opening the window early for - * the lower SFs. For higher SFs, the symbol time is large enough that we can - * afford to open late (hence the positive offset). - * The table below shows the calculated values for SF7 to SF12 with 125 kHz - * bandwidth. - * - * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ - * | SF | BW (kHz) | rx_error (ms) | wake_up (ms) | min_rx_symbols | window_timeout(symb) | window_offset(ms) | - * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ - * | 7 | 125 | 5 | 5 | 5 | 18 | -7 | - * | 8 | 125 | 5 | 5 | 5 | 10 | -4 | - * | 9 | 125 | 5 | 5 | 5 | 6 | 2 | - * | 10 | 125 | 5 | 5 | 5 | 6 | 14 | - * | 11 | 125 | 5 | 5 | 5 | 6 | 39 | - * | 12 | 125 | 5 | 5 | 5 | 6 | 88 | - * +----+-----+----------+---------+-------------------------+----------------------+-------------------------+ - * - * For example for SF7, the receive window will open at downlink start time - * plus the offset calculated and will remain open for the length window_timeout. - * - * Symbol time = 1.024 ms - * Downlink start: T = Tx + 1s (+/- 20 us) - * | - * | - * | - * | - * | - * +---+---+---+---+---+---+---+---+ - * | 8 Preamble Symbols | - * +---+---+---+---+---+---+---+---+ - * | RX Window start time = T +/- Offset - * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - * | | | | | | | | | | | | | | | | | | | - * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - * - * Similarly for SF12: - * - * Symbol time = 32.768 ms - * Downlink start: T = Tx + 1s (+/- 20 us) - * | - * | - * | - * | - * | - * +---+---+---+---+---+---+---+---+ - * | 8 Preamble Symbols | - * +---+---+---+---+---+---+---+---+ - * | RX Window start time = T +/- Offset - * +---+---+---+---+---+---+ - * | | | | | | | - * +---+---+---+---+---+---+ - */ - /*! - * Computes the RX window timeout and offset. - * - * @param [in] datarate The RX window datarate index to be used. - * - * @param [in] min_rx_symbols The minimum number of symbols required to - * detect an RX frame. - * - * @param [in] rx_error The maximum timing error of the receiver - * in milliseconds. The receiver will turn on - * in a [-rxError : +rxError] ms interval around - * RxOffset. - * - * @param [out] rx_conf_params Pointer to the structure that needs to be - * filled with receive window parameters. - * - */ - virtual void compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, - uint32_t rx_error, - rx_config_params_t *rx_conf_params); - - /** Configure radio transmission. - * - * @param [in] tx_config Structure containing tx parameters. - * - * @param [out] tx_power The TX power which will be set. - * - * @param [out] tx_toa The time-on-air of the frame. - * - * @return True, if the configuration was applied successfully. - */ - virtual bool tx_config(tx_config_params_t *tx_config, int8_t *tx_power, - lorawan_time_t *tx_toa); - - /** Processes a Link ADR Request. - * - * @param [in] params A pointer ADR request parameters. - * - * @param [out] dr_out The datarate applied. - * - * @param [out] tx_power_out The TX power applied. - * - * @param [out] nb_rep_out The number of repetitions to apply. - * - * @param [out] nb_bytes_parsed The number of bytes parsed. - * - * @return The status of the operation, according to the LoRaMAC specification. - */ - virtual uint8_t link_ADR_request(adr_req_params_t *params, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, - uint8_t *nb_bytes_parsed); - - /** Accept or rejects RxParamSetupReq MAC command - * - * The function processes a RX parameter setup request in response to - * server MAC command for RX setup. - * - * @param [in] params A pointer to rx parameter setup request. - * - * @return The status of the operation, according to the LoRaWAN specification. - */ - virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); - - /** - * @brief accept_tx_param_setup_req Makes decision whether to accept or reject TxParamSetupReq MAC command. - * - * @param ul_dwell_time The uplink dwell time. - * @param dl_dwell_time The downlink dwell time. - * - * @return True to let the MAC know that the request is - * accepted and MAC can apply TX parameters received - * form Network Server. Otherwise false is returned. - */ - virtual bool accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time); - - /** Processes a DlChannelReq MAC command. - * - * @param channel_id The channel ID to add the frequency. - * @param rx1_frequency The alternative frequency for the Rx1 window. - * - * @return The status of the operation, according to the LoRaWAN specification. - */ - virtual uint8_t dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency); - - /** Alternates the datarate of the channel for the join request. - * - * @param nb_trials Number of trials to be made on one given data rate. - * - * @return The datarate to apply . - */ - virtual int8_t get_alternate_DR(uint8_t nb_trials); - - /** Searches and sets the next available channel. - * - * If there are multiple channels found available, one of them is selected - * randomly. - * - * @param [in] nextChanParams Parameters for the next channel. - * - * @param [out] channel The next channel to use for TX. - * - * @param [out] time The time to wait for the next transmission according to the duty cycle. - * - * @param [out] aggregatedTimeOff Updates the aggregated time off. - * - * @return Function status [1: OK, 0: Unable to find a channel on the current datarate]. - */ - virtual lorawan_status_t set_next_channel(channel_selection_params_t *nextChanParams, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregatedTimeOff); - - /** Adds a channel to the channel list. - * - * Verifies the channel parameters and if everything is found legitimate, - * adds that particular channel to the channel list and updates the channel - * mask. - * - * @param [in] new_channel A pointer to the parameters for the new channel. - * @param [in] id Channel ID - * - * @return LORAWAN_STATUS_OK if everything goes fine, negative error code - * otherwise. - */ - virtual lorawan_status_t add_channel(const channel_params_t *new_channel, uint8_t id); - - /** Removes a channel from the channel list. - * - * @param [in] channel_id Index of the channel to be removed - * - * @return True, if the channel was removed successfully. - */ - virtual bool remove_channel(uint8_t channel_id); - - /** Puts the radio into continuous wave mode. - * - * @param [in] continuous_wave A pointer to the function parameters. - * - * @param [in] frequency Frequency to transmit at - */ - virtual void set_tx_cont_mode(cw_mode_params_t *continuous_wave, - uint32_t frequency = 0); - - /** Computes new data rate according to the given offset - * - * @param [in] dr The current datarate. - * - * @param [in] dr_offset The offset to be applied. - * - * @return The computed datarate. - */ - virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); - - /** - * @brief reset_to_default_values resets some parameters to default values - * @param params Pointer to MAC protocol parameters which will be reset - * @param init If true, most of the values will be modified - */ - void reset_to_default_values(loramac_protocol_params *params, bool init = false); - -public: - /** - * @brief get_next_lower_tx_datarate Gets the next lower datarate - * @param datarate Current TX datarate - * @return Lower datarate than given one or minimum if lower cannot be found anymore - */ - int8_t get_next_lower_tx_datarate(int8_t datarate); - - /** - * @brief get_minimum_rx_datarate Gets the minimum RX datarate supported by a device - * @return Minimum RX datarate - */ - uint8_t get_minimum_rx_datarate(); - - /** - * @brief get_minimum_tx_datarate Gets the minimum TX datarate supported by a device - * @return Minimum TX datarate - */ - uint8_t get_minimum_tx_datarate(); - - /** - * @brief get_default_tx_datarate Gets the default TX datarate - * @return default TX datarate - */ - uint8_t get_default_tx_datarate(); - - /** - * @brief get_default_max_tx_datarate Gets the maximum achievable data rate for - * LoRa modulation. This will always be the highest data rate achievable with - * LoRa as defined in the regional specifications. - * @return Maximum achievable data rate with LoRa modulation. - */ - uint8_t get_default_max_tx_datarate(); - - /** - * @brief get_default_tx_power Gets the default TX power - * @return Default TX power - */ - uint8_t get_default_tx_power(); - - /** - * @brief get_max_payload Gets maximum amount in bytes which device can send - * @param datarate A datarate to use - * @param use_repeater If true repeater table is used, otherwise payloads table is used - * @return Maximum number of bytes for payload - */ - uint8_t get_max_payload(uint8_t datarate, bool use_repeater = false); - - /** - * @brief get_maximum_frame_counter_gap Gets maximum frame counter gap - * @return Maximum frame counter gap - */ - uint16_t get_maximum_frame_counter_gap(); - - /** - * @brief get_ack_timeout Gets timeout value for ACK to be received - * @return ACK timeout - */ - uint32_t get_ack_timeout(); - - /** - * @brief get_default_rx2_frequency Gets default RX2 frequency - * @return RX2 frequency - */ - uint32_t get_default_rx2_frequency(); - - /** - * @brief get_default_rx2_datarate Gets default RX2 datarate - * @return RX2 datarate - */ - uint8_t get_default_rx2_datarate(); - - /** - * @brief get_channel_mask Gets the channel mask - * @param get_default If true the default mask is returned, otherwise the current mask is returned - * @return A channel mask - */ - uint16_t *get_channel_mask(bool get_default = false); - - /** - * @brief get_max_nb_channels Gets maximum number of channels supported - * @return Number of channels - */ - uint8_t get_max_nb_channels(); - - /** - * @brief get_phy_channels Gets PHY channels - * @return PHY channels - */ - channel_params_t *get_phy_channels(); - - /** - * @brief is_custom_channel_plan_supported Checks if custom channel plan is supported - * @return True if custom channel plan is supported, false otherwise - */ - bool is_custom_channel_plan_supported(); - - /** - * @brief get_rx_time_on_air(...) calculates the time the received spent on air - * @return time spent on air in milliseconds - */ - uint32_t get_rx_time_on_air(uint8_t modem, uint16_t pkt_len); - -public: //Verifiers - - /** - * @brief verify_rx_datarate Verifies that given RX datarate is valid - * @param datarate Datarate to check - * @return true if given datarate is valid, false otherwise - */ - bool verify_rx_datarate(uint8_t datarate); - - /** - * @brief verify_tx_datarate Verifies that given TX datarate is valid - * @param datarate Datarate to check - * @param use_default If true validation is done against default value - * @return true if given datarate is valid, false otherwise - */ - bool verify_tx_datarate(uint8_t datarate, bool use_default = false); - - /** - * @brief verify_tx_power Verifies that given TX power is valid - * @param tx_power Power to check - * @return True if valid, false otherwise - */ - bool verify_tx_power(uint8_t tx_power); - - /** - * @brief verify_duty_cycle Verifies that given cycle is valid - * @param cycle Cycle to check - * @return True if valid, false otherwise - */ - bool verify_duty_cycle(bool cycle); - - /** - * @brief verify_nb_join_trials Verifies that given number of trials is valid - * @param nb_join_trials Number to check - * @return True if valid, false otherwise - */ - bool verify_nb_join_trials(uint8_t nb_join_trials); - -protected: - LoRaPHY(); - - /** - * Looks up corresponding band for a frequency. Returns -1 if not in any band. - */ - int lookup_band_for_frequency(uint32_t freq) const; - - /** - * Verifies, if a frequency is within a given band. - */ - virtual bool verify_frequency_for_band(uint32_t freq, uint8_t band) const; - - /** - * Verifies, if a value is in a given range. - */ - bool val_in_range(int8_t value, int8_t min, int8_t max); - - /** - * Verifies, if a datarate is available on an active channel. - */ - bool verify_channel_DR(uint16_t *channelsMask, int8_t dr); - - /** - * Disables a channel in a given channels mask. - */ - bool disable_channel(uint16_t *channel_mask, uint8_t id, uint8_t max_channels); - - /** - * Counts number of bits on in a given mask - */ - uint8_t count_bits(uint16_t mask, uint8_t nb_bits); - - /** - * Counts the number of active channels in a given channels mask. - */ - uint8_t num_active_channels(uint16_t *channel_mask, uint8_t start_idx, - uint8_t stop_idx); - - /** - * Copy channel masks. - */ - void copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t len); - - /** - * Updates the time-offs of the bands. - */ - lorawan_time_t update_band_timeoff(bool joined, bool dutyCycle, band_t *bands, - uint8_t nb_bands); - - /** - * Parses the parameter of an LinkAdrRequest. - */ - uint8_t parse_link_ADR_req(const uint8_t *payload, uint8_t payload_size, - link_adr_params_t *adr_params); - - /** - * Verifies and updates the datarate, the TX power and the number of repetitions - * of a LinkAdrRequest. - */ - 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 RX window timeout and the RX window offset. - */ - void get_rx_window_params(float t_symbol, uint8_t min_rx_symbols, - float rx_error, float wakeup_time, - uint32_t *window_length, uint32_t *window_length_ms, - int32_t *window_offset, - uint8_t phy_dr); - - /** - * Computes the txPower, based on the max EIRP and the antenna gain. - */ - int8_t compute_tx_power(int8_t txPowerIndex, float maxEirp, float antennaGain); - - /** - * Provides a random number in the range provided. - */ - int32_t get_random(int32_t min, int32_t max); - - /** - * Get next lower data rate - */ - int8_t get_next_lower_dr(int8_t dr, int8_t min_dr); - - /** - * Get channel bandwidth depending upon data rate table index - */ - uint8_t get_bandwidth(uint8_t dr_index); - - uint8_t enabled_channel_count(uint8_t datarate, - const uint16_t *mask, uint8_t *enabledChannels, - uint8_t *delayTx); - - bool is_datarate_supported(const int8_t datarate) const; - -private: - - /** - * Computes the symbol time for LoRa modulation. - */ - float compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth); - - /** - * Computes the symbol time for FSK modulation. - */ - float compute_symb_timeout_fsk(uint8_t phy_dr); - -protected: - LoRaRadio *_radio; - LoRaWANTimeHandler *_lora_time; - loraphy_params_t phy_params; -}; - -#endif /* MBED_OS_LORAPHY_BASE_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp b/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp deleted file mode 100644 index e5e37e8..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/** - * @file LoRaPHYAS923.cpp - * - * @brief Implements LoRaPHY for Asia-Pacific 923 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYAS923.h" -#include "lora_phy_ds.h" - -/*! - * Number of default channels - */ -#define AS923_NUMB_DEFAULT_CHANNELS 2 - -/*! - * Number of channels to apply for the CF list - */ -#define AS923_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define AS923_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define AS923_TX_MAX_DATARATE DR_7 - -/*! - * Minimal datarate that can be used by the node - */ -#define AS923_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define AS923_RX_MAX_DATARATE DR_7 - -/*! - * Default datarate used by the node - */ -#define AS923_DEFAULT_DATARATE DR_2 - -#define AS923_DEFAULT_MAX_DATARATE DR_5 - -/*! - * The minimum datarate which is used when the - * dwell time is limited. - */ -#define AS923_DWELL_LIMIT_DATARATE DR_2 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define AS923_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define AS923_MAX_RX1_DR_OFFSET 7 - -/*! - * Default Rx1 receive datarate offset - */ -#define AS923_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define AS923_MIN_TX_POWER TX_POWER_7 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define AS923_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define AS923_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define AS923_DEFAULT_MAX_EIRP 16.0f - -/*! - * Default antenna gain - */ -#define AS923_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define AS923_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define AS923_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define AS923_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define AS923_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define AS923_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define AS923_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define AS923_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define AS923_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define AS923_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define AS923_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define AS923_ACK_TIMEOUT_RND 1000 - -#if ( AS923_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define AS923_RX_WND_2_FREQ 923200000 - -/*! - * Second reception window channel datarate definition. - */ -#define AS923_RX_WND_2_DR DR_2 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t AS923_BAND0 = {100, AS923_MAX_TX_POWER, 0, 0, 0, 923000000, 928000000}; // 1.0 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t AS923_LC1 = { 923200000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t AS923_LC2 = { 923400000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define AS923_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) ) - -/*! - * RSSI threshold for a free channel [dBm] - */ -#define AS923_RSSI_FREE_TH -85 - -/*! - * Specifies the time the node performs a carrier sense - */ -#define AS923_CARRIER_SENSE_TIME 6 - -/*! - * Data rates table definition - */ -static const uint8_t datarates_AS923[] = {12, 11, 10, 9, 8, 7, 7, 50}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_AS923[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; - -#if (MBED_CONF_LORA_DWELL_TIME == 0) -static const uint8_t max_payload_table[] = {51, 51, 51, 115, 242, 242, 242, 242}; -static const uint8_t max_payload_table_with_repeater[] = {51, 51, 51, 115, 222, 222, 222, 222}; -#else -// this is the default, i.e., -static const uint8_t max_payload_table[] = {0, 0, 11, 53, 125, 242, 242, 242}; -static const uint8_t max_payload_table_with_repeater[] = {0, 0, 11, 53, 125, 242, 242, 242}; -#endif - -/*! - * Effective datarate offsets for receive window 1. - */ -static const int8_t rx1_dr_offset_AS923[] = {0, 1, 2, 3, 4, 5, -1, -2}; - -LoRaPHYAS923::LoRaPHYAS923() -{ - bands[0] = AS923_BAND0; - - // Default Channels are always enabled in the channel list, - // rest will be added later - channels[0] = AS923_LC1; - channels[0].band = 0; - channels[1] = AS923_LC2; - channels[1].band = 0; - - // Initialize the default channel mask - default_channel_mask[0] = LC(1) + LC(2); - - // Update the channel mask list - copy_channel_mask(channel_mask, default_channel_mask, AS923_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = AS923_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = AS923_CHANNEL_MASK_SIZE; - - // set bands for AS923 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = AS923_MAX_NB_BANDS; - - // set bandwidths available in AS923 spectrum - phy_params.bandwidths.table = (void *) bandwidths_AS923; - phy_params.bandwidths.size = 8; - - // set data rates available in AS923 spectrum - phy_params.datarates.table = (void *) datarates_AS923; - phy_params.datarates.size = 8; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payload_table; - phy_params.payloads.size = 8; - phy_params.payloads_with_repeater.table = (void *) max_payload_table_with_repeater; - phy_params.payloads_with_repeater.size = 8; - - // dwell time setting, 400 ms - phy_params.ul_dwell_time_setting = 1; - phy_params.dl_dwell_time_setting = 1; - phy_params.dwell_limit_datarate = AS923_DWELL_LIMIT_DATARATE; - - phy_params.duty_cycle_enabled = AS923_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = true; - phy_params.fsk_supported = true; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = AS923_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = AS923_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = AS923_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = AS923_TX_MIN_DATARATE; - phy_params.max_tx_datarate = AS923_TX_MAX_DATARATE; - phy_params.min_rx_datarate = AS923_RX_MIN_DATARATE; - phy_params.max_rx_datarate = AS923_RX_MAX_DATARATE; - phy_params.default_datarate = AS923_DEFAULT_DATARATE; - phy_params.default_max_datarate = AS923_DEFAULT_MAX_DATARATE; - phy_params.min_rx1_dr_offset = AS923_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = AS923_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = AS923_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = AS923_MIN_TX_POWER; - phy_params.max_tx_power = AS923_MAX_TX_POWER; - phy_params.default_tx_power = AS923_DEFAULT_TX_POWER; - phy_params.default_max_eirp = AS923_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = AS923_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = AS923_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = AS923_ADR_ACK_DELAY; - phy_params.max_rx_window = AS923_MAX_RX_WINDOW; - phy_params.recv_delay1 = AS923_RECEIVE_DELAY1; - phy_params.recv_delay2 = AS923_RECEIVE_DELAY2; - phy_params.join_channel_mask = AS923_JOIN_CHANNELS; - phy_params.join_accept_delay1 = AS923_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = AS923_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = AS923_MAX_FCNT_GAP; - phy_params.ack_timeout = AS923_ACKTIMEOUT; - phy_params.ack_timeout_rnd = AS923_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = AS923_RX_WND_2_DR; - phy_params.rx_window2_frequency = AS923_RX_WND_2_FREQ; -} - -LoRaPHYAS923::~LoRaPHYAS923() -{ -} - -int8_t LoRaPHYAS923::get_alternate_DR(uint8_t nb_trials) -{ - // Only AS923_DWELL_LIMIT_DATARATE is supported - return AS923_DWELL_LIMIT_DATARATE; -} - -lorawan_status_t LoRaPHYAS923::set_next_channel(channel_selection_params_t *next_channel_prams, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff) -{ - uint8_t next_channel_idx = 0; - uint8_t nb_enabled_channels = 0; - uint8_t delay_tx = 0; - uint8_t enabled_channels[AS923_MAX_NB_CHANNELS] = { 0 }; - lorawan_time_t next_tx_delay = 0; - - if (num_active_channels(channel_mask, 0, 1) == 0) { - // Reactivate default channels - channel_mask[0] |= LC(1) + LC(2); - } - - if (next_channel_prams->aggregate_timeoff <= _lora_time->get_elapsed_time(next_channel_prams->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeoff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(next_channel_prams->joined, - next_channel_prams->dc_enabled, - bands, AS923_MAX_NB_BANDS); - - // Search how many channels are enabled - nb_enabled_channels = enabled_channel_count(next_channel_prams->current_datarate, - channel_mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = next_channel_prams->aggregate_timeoff - _lora_time->get_elapsed_time(next_channel_prams->last_aggregate_tx_time); - } - - if (nb_enabled_channels > 0) { - - _radio->lock(); - - for (uint8_t i = 0, j = get_random(0, nb_enabled_channels - 1); i < AS923_MAX_NB_CHANNELS; i++) { - next_channel_idx = enabled_channels[j]; - j = (j + 1) % nb_enabled_channels; - - // Perform carrier sense for AS923_CARRIER_SENSE_TIME - // If the channel is free, we can stop the LBT mechanism - - if (_radio->perform_carrier_sense(MODEM_LORA, - channels[next_channel_idx].frequency, - AS923_RSSI_FREE_TH, - AS923_CARRIER_SENSE_TIME) == true) { - // Free channel found - _radio->unlock(); - *channel = next_channel_idx; - *time = 0; - return LORAWAN_STATUS_OK; - } - } - _radio->unlock(); - return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; - } else { - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - // Datarate not supported by any channel, restore defaults - channel_mask[0] |= LC(1) + LC(2); - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; - } -} - -uint8_t LoRaPHYAS923::apply_DR_offset(int8_t dr, int8_t dr_offset) -{ - // Initialize minDr for a downlink dwell time configuration of 0 - int8_t min_dr = DR_0; - - // Update the minDR for a downlink dwell time configuration of 1 - if (phy_params.dl_dwell_time_setting == 1) { - min_dr = AS923_DWELL_LIMIT_DATARATE; - } - - // Apply offset formula - return MIN(DR_5, MAX(min_dr, dr - rx1_dr_offset_AS923[dr_offset])); -} - - diff --git a/features/lorawan/lorastack/phy/LoRaPHYAS923.h b/features/lorawan/lorastack/phy/LoRaPHYAS923.h deleted file mode 100644 index e222c0d..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYAS923.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file LoRaPHYAS923.h - * - * @brief Implements LoRaPHY for Asia-Pacific 923 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_AS923_H_ -#define MBED_OS_LORAPHY_AS923_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define AS923_MAX_NB_CHANNELS 16 - -/*! - * Maximum number of bands - */ -#define AS923_MAX_NB_BANDS 1 - -#define AS923_CHANNEL_MASK_SIZE 1 - -class LoRaPHYAS923 : public LoRaPHY { - -public: - LoRaPHYAS923(); - virtual ~LoRaPHYAS923(); - - virtual int8_t get_alternate_DR(uint8_t nb_trials); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t *nextChanParams, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregatedTimeOff); - - virtual uint8_t apply_DR_offset(int8_t dr, int8_t drOffset); - -private: - channel_params_t channels[AS923_MAX_NB_CHANNELS]; - band_t bands[AS923_MAX_NB_BANDS]; - uint16_t channel_mask[AS923_CHANNEL_MASK_SIZE]; - uint16_t default_channel_mask[AS923_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_AS923_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp deleted file mode 100644 index 24c8519..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +++ /dev/null @@ -1,663 +0,0 @@ -/** - * @file LoRaPHYAU915.cpp - * - * @brief Implements LoRaPHY for Australian 915 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include -#include "LoRaPHYAU915.h" -#include "lora_phy_ds.h" - -/*! - * Minimal datarate that can be used by the node - */ -#define AU915_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define AU915_TX_MAX_DATARATE DR_6 - -/*! - * Minimal datarate that can be used by the node - */ -#define AU915_RX_MIN_DATARATE DR_8 - -/*! - * Maximal datarate that can be used by the node - */ -#define AU915_RX_MAX_DATARATE DR_13 - -/*! - * Default datarate used by the node - */ -#define AU915_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define AU915_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define AU915_MAX_RX1_DR_OFFSET 6 - -/*! - * Default Rx1 receive datarate offset - */ -#define AU915_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define AU915_MIN_TX_POWER TX_POWER_10 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define AU915_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define AU915_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define AU915_DEFAULT_MAX_EIRP 30.0f - -/*! - * Default antenna gain - */ -#define AU915_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define AU915_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define AU915_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define AU915_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define AU915_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define AU915_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define AU915_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define AU915_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define AU915_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define AU915_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define AU915_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define AU915_ACK_TIMEOUT_RND 1000 - -/*! - * Second reception window channel frequency definition. - */ -#define AU915_RX_WND_2_FREQ 923300000 - -/*! - * Second reception window channel datarate definition. - */ -#define AU915_RX_WND_2_DR DR_8 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t AU915_BAND0 = {1, AU915_MAX_TX_POWER, 0, 0, 0, 915200000, 927800000}; // 100.0 % - -/*! - * Defines the first channel for RX window 1 for US band - */ -#define AU915_FIRST_RX1_CHANNEL ((uint32_t) 923300000) - -/*! - * Defines the last channel for RX window 1 for US band - */ -#define AU915_LAST_RX1_CHANNEL ((uint32_t) 927500000) - -/*! - * Defines the step width of the channels for RX window 1 - */ -#define AU915_STEPWIDTH_RX1_CHANNEL ((uint32_t) 600000) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_AU915[] = {12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_AU915[] = { 125000, 125000, 125000, 125000, - 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, - 0, 0 - }; - -/*! - * Up/Down link data rates offset definition - */ -static const int8_t datarate_offsets_AU915[7][6] = { { - DR_8, DR_8, DR_8, DR_8, - DR_8, DR_8 - }, // DR_0 - { DR_9, DR_8, DR_8, DR_8, DR_8, DR_8 }, // DR_1 - { DR_10, DR_9, DR_8, DR_8, DR_8, DR_8 }, // DR_2 - { DR_11, DR_10, DR_9, DR_8, DR_8, DR_8 }, // DR_3 - { DR_12, DR_11, DR_10, DR_9, DR_8, DR_8 }, // DR_4 - { DR_13, DR_12, DR_11, DR_10, DR_9, DR_8 }, // DR_5 - { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6 -}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payload_AU915[] = { 51, 51, 51, 115, 242, 242, - 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 - }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payload_with_repeater_AU915[] = { 51, 51, 51, 115, - 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 - }; - -static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; - -static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; - -LoRaPHYAU915::LoRaPHYAU915() -{ - bands[0] = AU915_BAND0; - - // Activate Channels - // 125 kHz channels Upstream only - for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++) { - channels[i].frequency = 915200000 + i * 200000; - channels[i].dr_range.value = (DR_5 << 4) | DR_0; - channels[i].band = 0; - } - // 500 kHz channels - // Upstream and downstream both - for (uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++) { - channels[i].frequency = 915900000 + (i - (AU915_MAX_NB_CHANNELS - 8)) * 1600000; - channels[i].dr_range.value = (DR_6 << 4) | DR_6; - channels[i].band = 0; - } - - // Initialize channels default mask - // All channels are default channels here - // Join request needs to alternate between 125 KHz and 500 KHz channels - // randomly. Fill in the default channel mask depending upon the given - // fsb_mask - fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, - default_channel_mask, AU915_CHANNEL_MASK_SIZE); - - memset(channel_mask, 0, sizeof(channel_mask)); - memset(current_channel_mask, 0, sizeof(current_channel_mask)); - - // Copy channels default mask - copy_channel_mask(channel_mask, default_channel_mask, AU915_CHANNEL_MASK_SIZE); - - // Copy into current channels mask - // This mask is used to keep track of the channels which were used in - // previous transmissions as the AU915 band doesn't allow concurrent - // transmission on the same channel - copy_channel_mask(current_channel_mask, channel_mask, AU915_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = AU915_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = AU915_CHANNEL_MASK_SIZE; - - // set bands for AU915 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = AU915_MAX_NB_BANDS; - - // set bandwidths available in AU915 spectrum - phy_params.bandwidths.table = (void *) bandwidths_AU915; - phy_params.bandwidths.size = 16; - - // set data rates available in AU915 spectrum - phy_params.datarates.table = (void *) datarates_AU915; - phy_params.datarates.size = 16; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payload_AU915; - phy_params.payloads.size = 16; - phy_params.payloads_with_repeater.table = (void *) max_payload_with_repeater_AU915; - phy_params.payloads_with_repeater.size = 16; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - phy_params.dwell_limit_datarate = AU915_DEFAULT_DATARATE; - - phy_params.duty_cycle_enabled = AU915_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.custom_channelplans_supported = false; - phy_params.cflist_supported = false; - phy_params.fsk_supported = false; - - phy_params.default_channel_cnt = AU915_MAX_NB_CHANNELS; - phy_params.max_channel_cnt = AU915_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = 0; - phy_params.min_tx_datarate = AU915_TX_MIN_DATARATE; - phy_params.max_tx_datarate = AU915_TX_MAX_DATARATE; - phy_params.min_rx_datarate = AU915_RX_MIN_DATARATE; - phy_params.max_rx_datarate = AU915_RX_MAX_DATARATE; - phy_params.default_datarate = AU915_DEFAULT_DATARATE; - phy_params.default_max_datarate = AU915_TX_MAX_DATARATE; - phy_params.min_rx1_dr_offset = AU915_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = AU915_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = AU915_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = AU915_MIN_TX_POWER; - phy_params.max_tx_power = AU915_MAX_TX_POWER; - phy_params.default_tx_power = AU915_DEFAULT_TX_POWER; - phy_params.default_max_eirp = AU915_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = AU915_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = AU915_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = AU915_ADR_ACK_DELAY; - phy_params.max_rx_window = AU915_MAX_RX_WINDOW; - phy_params.recv_delay1 = AU915_RECEIVE_DELAY1; - phy_params.recv_delay2 = AU915_RECEIVE_DELAY2; - - phy_params.join_accept_delay1 = AU915_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = AU915_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = AU915_MAX_FCNT_GAP; - phy_params.ack_timeout = AU915_ACKTIMEOUT; - phy_params.ack_timeout_rnd = AU915_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = AU915_RX_WND_2_DR; - phy_params.rx_window2_frequency = AU915_RX_WND_2_FREQ; -} - -LoRaPHYAU915::~LoRaPHYAU915() -{ -} - -bool LoRaPHYAU915::rx_config(rx_config_params_t *params) -{ - int8_t dr = params->datarate; - uint8_t max_payload = 0; - int8_t phy_dr = 0; - uint32_t frequency = params->frequency; - - if (_radio->get_status() != RF_IDLE) { - return false; - } - - if (params->rx_slot == RX_SLOT_WIN_1) { - // Apply window 1 frequency - frequency = AU915_FIRST_RX1_CHANNEL - + (params->channel % 8) * AU915_STEPWIDTH_RX1_CHANNEL; - // Caller may print the frequency to log so update it to match actual frequency - params->frequency = frequency; - } - - // Read the physical datarate from the datarates table - phy_dr = datarates_AU915[dr]; - - _radio->lock(); - - _radio->set_channel(frequency); - - // Radio configuration - _radio->set_rx_config(MODEM_LORA, params->bandwidth, phy_dr, 1, 0, 8, - params->window_timeout, false, 0, false, 0, 0, true, - params->is_rx_continuous); - - if (params->is_repeater_supported == true) { - max_payload = max_payload_with_repeater_AU915[dr]; - } else { - max_payload = max_payload_AU915[dr]; - } - _radio->set_max_payload_length(MODEM_LORA, - max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - _radio->unlock(); - - return true; -} - -bool LoRaPHYAU915::tx_config(tx_config_params_t *params, int8_t *tx_power, - lorawan_time_t *tx_toa) -{ - int8_t phy_dr = datarates_AU915[params->datarate]; - - if (params->tx_power > bands[channels[params->channel].band].max_tx_pwr) { - params->tx_power = bands[channels[params->channel].band].max_tx_pwr; - } - - uint32_t bandwidth = get_bandwidth(params->datarate); - int8_t phy_tx_power = 0; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp, - params->antenna_gain); - - // setting up radio tx configurations - - _radio->lock(); - - _radio->set_channel(channels[params->channel].frequency); - - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, - false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(MODEM_LORA, params->pkt_len); - - *tx_toa = _radio->time_on_air(MODEM_LORA, params->pkt_len); - - _radio->unlock(); - - *tx_power = params->tx_power; - - return true; -} - -uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t *params, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, - uint8_t *nb_bytes_parsed) -{ - uint8_t status = 0x07; - link_adr_params_t adr_settings = {}; - uint8_t next_index = 0; - uint8_t bytes_processed = 0; - uint16_t temp_channel_masks[AU915_CHANNEL_MASK_SIZE] = { 0, 0, 0, 0, 0}; - - verify_adr_params_t verify_params; - - // Initialize local copy of channels mask - copy_channel_mask(temp_channel_masks, channel_mask, AU915_CHANNEL_MASK_SIZE); - - while (bytes_processed < params->payload_size && - params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { - next_index = parse_link_ADR_req(&(params->payload[bytes_processed]), - params->payload_size, - &adr_settings); - - if (next_index == 0) { - bytes_processed = 0; - // break loop, malformed packet - break; - } - - // Update bytes processed - bytes_processed += next_index; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (adr_settings.ch_mask_ctrl == 6) { - // Enable all 125 kHz channels - fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, - AU915_CHANNEL_MASK_SIZE - 1); - - // Apply chMask to channels 64 to 71 - temp_channel_masks[4] = adr_settings.channel_mask; - } else if (adr_settings.ch_mask_ctrl == 7) { - // Disable all 125 kHz channels - fill_channel_mask_with_value(temp_channel_masks, 0x0000, - AU915_CHANNEL_MASK_SIZE - 1); - - // Apply chMask to channels 64 to 71 - temp_channel_masks[4] = adr_settings.channel_mask; - } else if (adr_settings.ch_mask_ctrl == 5) { - // RFU - status &= 0xFE; // Channel mask KO - } else { - temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; - } - } - - if (bytes_processed == 0) { - *nb_bytes_parsed = 0; - return status; - } - - // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels - if ((adr_settings.datarate < DR_6) - && (num_active_channels(temp_channel_masks, 0, 4) < 2)) { - status &= 0xFE; // Channel mask KO - } - - verify_params.status = status; - verify_params.adr_enabled = params->adr_enabled; - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; - verify_params.current_datarate = params->current_datarate; - verify_params.current_tx_power = params->current_tx_power; - verify_params.current_nb_rep = params->current_nb_trans; - verify_params.channel_mask = temp_channel_masks; - - - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); - - // Update cchannel mask if everything is correct - if (status == 0x07) { - // Copy Mask - copy_channel_mask(channel_mask, temp_channel_masks, AU915_CHANNEL_MASK_SIZE); - - intersect_channel_mask(channel_mask, current_channel_mask, - AU915_CHANNEL_MASK_SIZE); - } - - // Update status variables - *dr_out = adr_settings.datarate; - *tx_power_out = adr_settings.tx_power; - *nb_rep_out = adr_settings.nb_rep; - *nb_bytes_parsed = bytes_processed; - - return status; -} - -uint8_t LoRaPHYAU915::accept_rx_param_setup_req(rx_param_setup_req_t *params) -{ - uint8_t status = 0x07; - uint32_t freq = params->frequency; - - // Verify radio frequency - _radio->lock(); - - if ((_radio->check_rf_frequency(freq) == false) - || (freq < AU915_FIRST_RX1_CHANNEL) - || (freq > AU915_LAST_RX1_CHANNEL) - || (((freq - (uint32_t) AU915_FIRST_RX1_CHANNEL) - % (uint32_t) AU915_STEPWIDTH_RX1_CHANNEL) != 0)) { - status &= 0xFE; // Channel frequency KO - } - - _radio->unlock(); - - // Verify datarate - if (val_in_range(params->datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE) == 0) { - status &= 0xFD; // Datarate KO - } - - if ((params->datarate == DR_7) || (params->datarate > DR_13)) { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (val_in_range(params->dr_offset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET) == 0) { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; -} - -int8_t LoRaPHYAU915::get_alternate_DR(uint8_t nb_trials) -{ - int8_t datarate = 0; - - if ((nb_trials & 0x01) == 0x01) { - datarate = DR_6; - } else { - datarate = DR_0; - } - - return datarate; -} - -lorawan_status_t LoRaPHYAU915::set_next_channel(channel_selection_params_t *next_chan_params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregated_timeOff) -{ - uint8_t nb_enabled_channels = 0; - uint8_t delay_tx = 0; - uint8_t enabled_channels[AU915_MAX_NB_CHANNELS] = { 0 }; - lorawan_time_t next_tx_delay = 0; - - // Count 125kHz channels - if (num_active_channels(current_channel_mask, 0, 4) == 0) { - // Reactivate 125 kHz default channels - copy_channel_mask(current_channel_mask, channel_mask, 4); - } - - // Check other channels - if ((next_chan_params->current_datarate >= DR_6) - && (current_channel_mask[4] & 0x00FF) == 0) { - // fall back to 500 kHz default channels - current_channel_mask[4] = channel_mask[4]; - } - - if (next_chan_params->aggregate_timeoff <= _lora_time->get_elapsed_time(next_chan_params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregated_timeOff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(next_chan_params->joined, - next_chan_params->dc_enabled, - bands, AU915_MAX_NB_BANDS); - - // Search how many channels are enabled - nb_enabled_channels = enabled_channel_count(next_chan_params->current_datarate, - current_channel_mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = next_chan_params->aggregate_timeoff - _lora_time->get_elapsed_time(next_chan_params->last_aggregate_tx_time); - } - - if (nb_enabled_channels > 0) { - // We found a valid channel - *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; - // Disable the channel in the mask - disable_channel(current_channel_mask, *channel, AU915_MAX_NB_CHANNELS); - - *time = 0; - return LORAWAN_STATUS_OK; - } else { - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - // Datarate not supported by any channel - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; - } -} - -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 deleted file mode 100644 index cdcce73..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @file LoRaPHYAU915.h - * - * @brief Implements LoRaPHY for Australian 915 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_AU915_H_ - -#define MBED_OS_LORAPHY_AU915_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -// Definitions -/*! - * LoRaMac maximum number of channels - */ -#define AU915_MAX_NB_CHANNELS 72 - -/*! - * LoRaMac maximum number of bands - */ -#define AU915_MAX_NB_BANDS 1 - -#define AU915_CHANNEL_MASK_SIZE 5 - -class LoRaPHYAU915 : public LoRaPHY { - -public: - - LoRaPHYAU915(); - virtual ~LoRaPHYAU915(); - - virtual bool rx_config(rx_config_params_t *config); - - virtual bool tx_config(tx_config_params_t *config, int8_t *txPower, - lorawan_time_t *txTimeOnAir); - - virtual uint8_t link_ADR_request(adr_req_params_t *params, - int8_t *drOut, int8_t *txPowOut, - uint8_t *nbRepOut, - uint8_t *nbBytesParsed); - - virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); - - virtual int8_t get_alternate_DR(uint8_t nb_trials); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t *next_chan_params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff); - - 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: - - /*! - * LoRaMAC channels - */ - channel_params_t channels[AU915_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[AU915_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[AU915_CHANNEL_MASK_SIZE]; - - /*! - * Previously used channel mask - */ - uint16_t current_channel_mask[AU915_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac channels default mask - */ - uint16_t default_channel_mask[AU915_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_AU915_H_ */ - diff --git a/features/lorawan/lorastack/phy/LoRaPHYCN470.cpp b/features/lorawan/lorastack/phy/LoRaPHYCN470.cpp deleted file mode 100644 index 3385cfe..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYCN470.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/** - * @file LoRaPHYCN470.cpp - * - * @brief Implements LoRaPHY for Chinese 470 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYCN470.h" -#include "lora_phy_ds.h" - -/*! - * Minimal datarate that can be used by the node - */ -#define CN470_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define CN470_TX_MAX_DATARATE DR_5 - -/*! - * Minimal datarate that can be used by the node - */ -#define CN470_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define CN470_RX_MAX_DATARATE DR_5 - -/*! - * Default datarate used by the node - */ -#define CN470_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define CN470_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define CN470_MAX_RX1_DR_OFFSET 3 - -/*! - * Default Rx1 receive datarate offset - */ -#define CN470_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define CN470_MIN_TX_POWER TX_POWER_7 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define CN470_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define CN470_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define CN470_DEFAULT_MAX_EIRP 19.15f - -/*! - * Default antenna gain - */ -#define CN470_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define CN470_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define CN470_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define CN470_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define CN470_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define CN470_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define CN470_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define CN470_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define CN470_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define CN470_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define CN470_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define CN470_ACK_TIMEOUT_RND 1000 - -/*! - * Second reception window channel frequency definition. - */ -#define CN470_RX_WND_2_FREQ 505300000 - -/*! - * Second reception window channel datarate definition. - */ -#define CN470_RX_WND_2_DR DR_0 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t CN470_BAND0 = {1, CN470_MAX_TX_POWER, 0, 0, 0}; // 100.0 % - -/*! - * Defines the first channel for RX window 1 for CN470 band - */ -#define CN470_FIRST_RX1_CHANNEL ((uint32_t) 500300000) - -/*! - * Defines the last channel for RX window 1 for CN470 band - */ -#define CN470_LAST_RX1_CHANNEL ((uint32_t) 509700000) - -/*! - * Defines the step width of the channels for RX window 1 - */ -#define CN470_STEPWIDTH_RX1_CHANNEL ((uint32_t) 200000) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_CN470[] = {12, 11, 10, 9, 8, 7}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_CN470[] = {125000, 125000, 125000, 125000, 125000, 125000}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_CN470[] = {51, 51, 51, 115, 222, 222}; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_CN470[] = {51, 51, 51, 115, 222, 222}; - - -LoRaPHYCN470::LoRaPHYCN470() -{ - static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK_CHINA; - - bands[0] = CN470_BAND0; - - // Channels - // 125 kHz channels - for (uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++) { - channels[i].frequency = 470300000 + i * 200000; - channels[i].dr_range.value = (DR_5 << 4) | DR_0; - channels[i].band = 0; - } - - // Initialize the channels default mask - for (uint8_t i = 0; i < CN470_CHANNEL_MASK_SIZE; i++) { - default_channel_mask[i] = 0xFFFF & fsb_mask[i]; - } - - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, CN470_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = CN470_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = CN470_CHANNEL_MASK_SIZE; - - // set bands for CN470 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = CN470_MAX_NB_BANDS; - - // set bandwidths available in CN470 spectrum - phy_params.bandwidths.table = (void *) bandwidths_CN470; - phy_params.bandwidths.size = 6; - - // set data rates available in CN470 spectrum - phy_params.datarates.table = (void *) datarates_CN470; - phy_params.datarates.size = 6; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_CN470; - phy_params.payloads.size = 6; - phy_params.payloads_with_repeater.table = (void *)max_payloads_with_repeater_CN470; - phy_params.payloads_with_repeater.size = 6; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = CN470_DUTY_CYCLE_ENABLED; - - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = false; - phy_params.cflist_supported = false; - phy_params.dl_channel_req_supported = false; - phy_params.custom_channelplans_supported = false; - - phy_params.default_channel_cnt = CN470_MAX_NB_CHANNELS; - phy_params.max_channel_cnt = CN470_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = 0; - phy_params.min_tx_datarate = CN470_TX_MIN_DATARATE; - phy_params.max_tx_datarate = CN470_TX_MAX_DATARATE; - phy_params.min_rx_datarate = CN470_RX_MIN_DATARATE; - phy_params.max_rx_datarate = CN470_RX_MAX_DATARATE; - phy_params.default_datarate = CN470_DEFAULT_DATARATE; - phy_params.default_max_datarate = CN470_TX_MAX_DATARATE; - phy_params.min_rx1_dr_offset = CN470_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = CN470_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = CN470_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = CN470_MIN_TX_POWER; - phy_params.max_tx_power = CN470_MAX_TX_POWER; - phy_params.default_tx_power = CN470_DEFAULT_TX_POWER; - phy_params.default_max_eirp = CN470_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = CN470_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = CN470_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = CN470_ADR_ACK_DELAY; - phy_params.max_rx_window = CN470_MAX_RX_WINDOW; - phy_params.recv_delay1 = CN470_RECEIVE_DELAY1; - phy_params.recv_delay2 = CN470_RECEIVE_DELAY2; - - phy_params.join_accept_delay1 = CN470_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = CN470_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = CN470_MAX_FCNT_GAP; - phy_params.ack_timeout = CN470_ACKTIMEOUT; - phy_params.ack_timeout_rnd = CN470_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = CN470_RX_WND_2_DR; - phy_params.rx_window2_frequency = CN470_RX_WND_2_FREQ; -} - -LoRaPHYCN470::~LoRaPHYCN470() -{ -} - -lorawan_status_t LoRaPHYCN470::set_next_channel(channel_selection_params_t *params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff) -{ - uint8_t channel_count = 0; - uint8_t delay_tx = 0; - - uint8_t enabled_channels[CN470_MAX_NB_CHANNELS] = {0}; - - lorawan_time_t next_tx_delay = 0; - band_t *band_table = (band_t *) phy_params.bands.table; - - if (num_active_channels(phy_params.channels.mask, 0, - phy_params.channels.mask_size) == 0) { - - // Reactivate default channels - copy_channel_mask(phy_params.channels.mask, - phy_params.channels.default_mask, - phy_params.channels.mask_size); - } - - if (params->aggregate_timeoff - <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeoff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(params->joined, - params->dc_enabled, - band_table, phy_params.bands.size); - - // Search how many channels are enabled - channel_count = enabled_channel_count(params->current_datarate, - phy_params.channels.mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = params->aggregate_timeoff - - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); - } - - if (channel_count > 0) { - // We found a valid channel - *channel = enabled_channels[get_random(0, channel_count - 1)]; - *time = 0; - return LORAWAN_STATUS_OK; - } - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; -} - -bool LoRaPHYCN470::rx_config(rx_config_params_t *config) -{ - int8_t dr = config->datarate; - uint8_t max_payload = 0; - int8_t phy_dr = 0; - uint32_t frequency = config->frequency; - - _radio->lock(); - - if (_radio->get_status() != RF_IDLE) { - _radio->unlock(); - return false; - } - - _radio->unlock(); - - if (config->rx_slot == RX_SLOT_WIN_1) { - // Apply window 1 frequency - frequency = CN470_FIRST_RX1_CHANNEL + (config->channel % 48) * CN470_STEPWIDTH_RX1_CHANNEL; - // Caller may print the frequency to log so update it to match actual frequency - config->frequency = frequency; - } - - // Read the physical datarate from the datarates table - phy_dr = datarates_CN470[dr]; - - _radio->lock(); - - _radio->set_channel(frequency); - - // Radio configuration - _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, - MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, - config->window_timeout, false, 0, false, 0, 0, true, - config->is_rx_continuous); - - _radio->unlock(); - - if (config->is_repeater_supported == true) { - max_payload = max_payloads_with_repeater_CN470[dr]; - } else { - max_payload = max_payloads_CN470[dr]; - } - - _radio->lock(); - _radio->set_max_payload_length(MODEM_LORA, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - _radio->unlock(); - - return true; -} - -bool LoRaPHYCN470::tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa) -{ - int8_t phy_dr = datarates_CN470[config->datarate]; - - if (config->tx_power > bands[channels[config->channel].band].max_tx_pwr) { - config->tx_power = bands[channels[config->channel].band].max_tx_pwr; - } - - int8_t phy_tx_power = 0; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(config->tx_power, config->max_eirp, - config->antenna_gain); - - // acquire lock to radio - _radio->lock(); - - _radio->set_channel(channels[config->channel].frequency); - - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, 0, phy_dr, 1, - MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, false, true, - 0, 0, false, 3000); - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); - - // Get the time-on-air of the next tx frame - *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); - - // release lock to radio - _radio->unlock(); - - *tx_power = config->tx_power; - - return true; -} - -uint8_t LoRaPHYCN470::link_ADR_request(adr_req_params_t *params, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, - uint8_t *nb_bytes_parsed) -{ - uint8_t status = 0x07; - link_adr_params_t adr_settings; - uint8_t next_index = 0; - uint8_t bytes_processed = 0; - uint16_t temp_channel_masks[CN470_CHANNEL_MASK_SIZE] = {0, 0, 0, 0, 0, 0}; - - verify_adr_params_t verify_params; - - // Initialize local copy of channels mask - copy_channel_mask(temp_channel_masks, channel_mask, CN470_CHANNEL_MASK_SIZE); - - while (bytes_processed < params->payload_size && - params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { - - // Get ADR request parameters - next_index = parse_link_ADR_req(&(params->payload[bytes_processed]), - params->payload_size, - &adr_settings); - - if (next_index == 0) { - bytes_processed = 0; - // break loop, malformed packet - break; - } - - // Update bytes processed - bytes_processed += next_index; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (adr_settings.ch_mask_ctrl == 6) { - - // Enable all 125 kHz channels - for (uint8_t i = 0; i < CN470_CHANNEL_MASK_SIZE; i++) { - temp_channel_masks[i] = 0xFFFF; - } - - } else if (adr_settings.ch_mask_ctrl == 7) { - - status &= 0xFE; // Channel mask KO - - } else { - - for (uint8_t i = 0; i < 16; i++) { - - if (((adr_settings.channel_mask & (1 << i)) != 0) && - (channels[adr_settings.ch_mask_ctrl * 16 + i].frequency == 0)) { - // Trying to enable an undefined channel - status &= 0xFE; // Channel mask KO - } - } - - temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; - } - } - - if (bytes_processed == 0) { - *nb_bytes_parsed = 0; - return status; - } - - verify_params.status = status; - verify_params.adr_enabled = params->adr_enabled; - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; - verify_params.current_datarate = params->current_datarate; - verify_params.current_tx_power = params->current_tx_power; - verify_params.current_nb_rep = params->current_nb_trans; - verify_params.channel_mask = temp_channel_masks; - - - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); - - // Update channelsMask if everything is correct - if (status == 0x07) { - // Copy Mask - copy_channel_mask(channel_mask, temp_channel_masks, CN470_CHANNEL_MASK_SIZE); - } - - // Update status variables - *dr_out = adr_settings.datarate; - *tx_power_out = adr_settings.tx_power; - *nb_rep_out = adr_settings.nb_rep; - *nb_bytes_parsed = bytes_processed; - - return status; -} - -uint8_t LoRaPHYCN470::accept_rx_param_setup_req(rx_param_setup_req_t *params) -{ - uint8_t status = 0x07; - uint32_t freq = params->frequency; - - // acquire radio lock - _radio->lock(); - - if ((_radio->check_rf_frequency(freq) == false) - || (freq < CN470_FIRST_RX1_CHANNEL) - || (freq > CN470_LAST_RX1_CHANNEL) - || (((freq - (uint32_t) CN470_FIRST_RX1_CHANNEL) % (uint32_t) CN470_STEPWIDTH_RX1_CHANNEL) != 0)) { - - status &= 0xFE; // Channel frequency KO - } - - // release radio lock - _radio->unlock(); - - // Verify datarate - if (val_in_range(params->datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE) == 0) { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (val_in_range(params->dr_offset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET) == 0) { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; -} diff --git a/features/lorawan/lorastack/phy/LoRaPHYCN470.h b/features/lorawan/lorastack/phy/LoRaPHYCN470.h deleted file mode 100644 index 81d07a2..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYCN470.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file LoRaPHYCN470.h - * - * @brief Implements LoRaPHY for Chinese 470 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_CN470_H_ -#define MBED_OS_LORAPHY_CN470_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -// Definitions -/*! - * LoRaMac maximum number of channels - */ -#define CN470_MAX_NB_CHANNELS 96 - -/*! - * LoRaMac maximum number of bands - */ -#define CN470_MAX_NB_BANDS 1 - - -#define CN470_CHANNEL_MASK_SIZE 6 - - -class LoRaPHYCN470 : public LoRaPHY { - -public: - - LoRaPHYCN470(); - virtual ~LoRaPHYCN470(); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff); - - virtual bool rx_config(rx_config_params_t *config); - - virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa); - - virtual uint8_t link_ADR_request(adr_req_params_t *params, int8_t *dr_out, - int8_t *tx_power_out, uint8_t *nb_rep_out, - uint8_t *nb_bytes_parsed); - - virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); - -private: - - /*! - * LoRaMAC channels - */ - channel_params_t channels[CN470_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[CN470_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[CN470_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[CN470_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_CN470_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYCN779.cpp b/features/lorawan/lorastack/phy/LoRaPHYCN779.cpp deleted file mode 100644 index d19e95e..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYCN779.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file LoRaPHYCN779.cpp - * - * @brief Implements LoRaPHY for Chinese 779 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYCN779.h" -#include "lora_phy_ds.h" - -/*! - * Number of default channels - */ -#define CN779_NUMB_DEFAULT_CHANNELS 3 - -/*! - * Number of channels to apply for the CF list - */ -#define CN779_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define CN779_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define CN779_TX_MAX_DATARATE DR_7 - -/*! - * Minimal datarate that can be used by the node - */ -#define CN779_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define CN779_RX_MAX_DATARATE DR_7 - -#define CN779_DEFAULT_MAX_DATARATE DR_5 - -/*! - * Default datarate used by the node - */ -#define CN779_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define CN779_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define CN779_MAX_RX1_DR_OFFSET 5 - -/*! - * Default Rx1 receive datarate offset - */ -#define CN779_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define CN779_MIN_TX_POWER TX_POWER_5 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define CN779_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define CN779_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define CN779_DEFAULT_MAX_EIRP 12.15f - -/*! - * Default antenna gain - */ -#define CN779_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define CN779_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define CN779_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define CN779_DUTY_CYCLE_ENABLED 1 - -/*! - * Maximum RX window duration - */ -#define CN779_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define CN779_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define CN779_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define CN779_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define CN779_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define CN779_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define CN779_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define CN779_ACK_TIMEOUT_RND 1000 - -/*! - * Verification of default datarate - */ -#if ( CN779_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define CN779_RX_WND_2_FREQ 786000000 - -/*! - * Second reception window channel datarate definition. - */ -#define CN779_RX_WND_2_DR DR_0 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t CN779_BAND0 = {100, CN779_MAX_TX_POWER, 0, 0, 0, 779500000, 786500000}; // 1.0 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t CN779_LC1 = {779500000, 0, { ((DR_5 << 4) | DR_0) }, 0}; -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t CN779_LC2 = {779700000, 0, { ((DR_5 << 4) | DR_0) }, 0}; - -/*! - * LoRaMac default channel 3 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t CN779_LC3 = {779900000, 0, { ((DR_5 << 4) | DR_0) }, 0}; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define CN779_JOIN_CHANNELS (uint16_t) (LC(1) | LC(2) | LC(3)) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_CN779[] = {12, 11, 10, 9, 8, 7, 7, 50}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_CN779[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_CN779[] = {51, 51, 51, 115, 242, 242, 242, 242}; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_CN779[] = {51, 51, 51, 115, 222, 222, 222, 222}; - - -LoRaPHYCN779::LoRaPHYCN779() -{ - bands[0] = CN779_BAND0; - - // Channels - channels[0] = CN779_LC1; - channels[0].band = 0; - channels[1] = CN779_LC2; - channels[1].band = 0; - channels[2] = CN779_LC3; - channels[2].band = 0; - - // Initialize the channels default mask - default_channel_mask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, CN779_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = CN779_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = CN779_CHANNEL_MASK_SIZE; - - // set bands for CN779 spectrum - phy_params.bands.table = bands; - phy_params.bands.size = CN779_MAX_NB_BANDS; - - // set bandwidths available in CN779 spectrum - phy_params.bandwidths.table = (void *) bandwidths_CN779; - phy_params.bandwidths.size = 8; - - // set data rates available in CN779 spectrum - phy_params.datarates.table = (void *) datarates_CN779; - phy_params.datarates.size = 8; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_CN779; - phy_params.payloads.size = 8; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_CN779; - phy_params.payloads_with_repeater.size = 8; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = CN779_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = true; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = CN779_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = CN779_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = CN779_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = CN779_TX_MIN_DATARATE; - phy_params.max_tx_datarate = CN779_TX_MAX_DATARATE; - phy_params.min_rx_datarate = CN779_RX_MIN_DATARATE; - phy_params.max_rx_datarate = CN779_RX_MAX_DATARATE; - phy_params.default_datarate = CN779_DEFAULT_DATARATE; - phy_params.default_max_datarate = CN779_DEFAULT_MAX_DATARATE; - phy_params.min_rx1_dr_offset = CN779_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = CN779_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = CN779_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = CN779_MIN_TX_POWER; - phy_params.max_tx_power = CN779_MAX_TX_POWER; - phy_params.default_tx_power = CN779_DEFAULT_TX_POWER; - phy_params.default_max_eirp = CN779_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = CN779_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = CN779_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = CN779_ADR_ACK_DELAY; - phy_params.max_rx_window = CN779_MAX_RX_WINDOW; - phy_params.recv_delay1 = CN779_RECEIVE_DELAY1; - phy_params.recv_delay2 = CN779_RECEIVE_DELAY2; - phy_params.join_channel_mask = CN779_JOIN_CHANNELS; - phy_params.join_accept_delay1 = CN779_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = CN779_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = CN779_MAX_FCNT_GAP; - phy_params.ack_timeout = CN779_ACKTIMEOUT; - phy_params.ack_timeout_rnd = CN779_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = CN779_RX_WND_2_DR; - phy_params.rx_window2_frequency = CN779_RX_WND_2_FREQ; -} - -LoRaPHYCN779::~LoRaPHYCN779() -{ -} - diff --git a/features/lorawan/lorastack/phy/LoRaPHYCN779.h b/features/lorawan/lorastack/phy/LoRaPHYCN779.h deleted file mode 100644 index 2531a89..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYCN779.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file LoRaPHYCN779.h - * - * @brief Implements LoRaPHY for Chinese 779 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_CN779_H_ -#define MBED_OS_LORAPHY_CN779_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -#define CN779_MAX_NB_CHANNELS 16 - -#define CN779_MAX_NB_BANDS 1 - -#define CN779_CHANNEL_MASK_SIZE 1 - - -class LoRaPHYCN779 : public LoRaPHY { - -public: - - LoRaPHYCN779(); - virtual ~LoRaPHYCN779(); - -private: - /*! - * LoRaMAC channels - */ - channel_params_t channels[CN779_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[CN779_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[CN779_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[CN779_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_CN779_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYEU433.cpp b/features/lorawan/lorastack/phy/LoRaPHYEU433.cpp deleted file mode 100644 index 50d60ff..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYEU433.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file LoRaPHYEU433.cpp - * - * @brief Implements LoRaPHY for European 433 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYEU433.h" -#include "lora_phy_ds.h" - -/*! - * Number of default channels - */ -#define EU433_NUMB_DEFAULT_CHANNELS 3 - -/*! - * Number of channels to apply for the CF list - */ -#define EU433_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define EU433_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define EU433_TX_MAX_DATARATE DR_7 - -/*! - * Minimal datarate that can be used by the node - */ -#define EU433_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define EU433_RX_MAX_DATARATE DR_7 - -/*! - * Default datarate used by the node - */ -#define EU433_DEFAULT_DATARATE DR_0 - -#define EU433_DEFAULT_MAX_DATARATE DR_5 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define EU433_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define EU433_MAX_RX1_DR_OFFSET 5 - -/*! - * Default Rx1 receive datarate offset - */ -#define EU433_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define EU433_MIN_TX_POWER TX_POWER_5 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define EU433_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define EU433_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define EU433_DEFAULT_MAX_EIRP 12.15f - -/*! - * Default antenna gain - */ -#define EU433_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define EU433_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define EU433_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define EU433_DUTY_CYCLE_ENABLED 1 - -/*! - * Maximum RX window duration - */ -#define EU433_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define EU433_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define EU433_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define EU433_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define EU433_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define EU433_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define EU433_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define EU433_ACK_TIMEOUT_RND 1000 - -/*! - * Verification of default datarate - */ -#if ( EU433_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define EU433_RX_WND_2_FREQ 434665000 - -/*! - * Second reception window channel datarate definition. - */ -#define EU433_RX_WND_2_DR DR_0 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU433_BAND0 = {100, EU433_MAX_TX_POWER, 0, 0, 0, 433175000, 434665000}; // 1.0 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU433_LC1 = {433175000, 0, { ((DR_5 << 4) | DR_0) }, 0}; - -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU433_LC2 = {433375000, 0, { ((DR_5 << 4) | DR_0) }, 0}; - -/*! - * LoRaMac default channel 3 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU433_LC3 = {433575000, 0, { ((DR_5 << 4) | DR_0) }, 0}; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define EU433_JOIN_CHANNELS (uint16_t) (LC(1) | LC(2) | LC(3)) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_EU433[] = {12, 11, 10, 9, 8, 7, 7, 50}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_EU433[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_EU433[] = {51, 51, 51, 115, 242, 242, 242, 242}; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_EU433[] = {51, 51, 51, 115, 222, 222, 222, 222}; - - -LoRaPHYEU433::LoRaPHYEU433() -{ - bands[0] = EU433_BAND0; - - // Channels - channels[0] = EU433_LC1; - channels[0].band = 0; - channels[1] = EU433_LC2; - channels[1].band = 0; - channels[2] = EU433_LC3; - channels[2].band = 0; - - // Initialize the channels default mask - default_channel_mask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, EU433_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = EU433_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = EU433_CHANNEL_MASK_SIZE; - - // set bands for EU433 spectrum - phy_params.bands.table = bands; - phy_params.bands.size = EU433_MAX_NB_BANDS; - - // set bandwidths available in EU433 spectrum - phy_params.bandwidths.table = (void *) bandwidths_EU433; - phy_params.bandwidths.size = 8; - - // set data rates available in EU433 spectrum - phy_params.datarates.table = (void *) datarates_EU433; - phy_params.datarates.size = 8; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_EU433; - phy_params.payloads.size = 8; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_EU433; - phy_params.payloads_with_repeater.size = 8; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = EU433_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = true; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = EU433_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = EU433_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = EU433_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = EU433_TX_MIN_DATARATE; - phy_params.max_tx_datarate = EU433_TX_MAX_DATARATE; - phy_params.min_rx_datarate = EU433_RX_MIN_DATARATE; - phy_params.max_rx_datarate = EU433_RX_MAX_DATARATE; - phy_params.default_datarate = EU433_DEFAULT_DATARATE; - phy_params.default_max_datarate = EU433_DEFAULT_MAX_DATARATE; - phy_params.min_rx1_dr_offset = EU433_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = EU433_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = EU433_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = EU433_MIN_TX_POWER; - phy_params.max_tx_power = EU433_MAX_TX_POWER; - phy_params.default_tx_power = EU433_DEFAULT_TX_POWER; - phy_params.default_max_eirp = EU433_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = EU433_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = EU433_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = EU433_ADR_ACK_DELAY; - phy_params.max_rx_window = EU433_MAX_RX_WINDOW; - phy_params.recv_delay1 = EU433_RECEIVE_DELAY1; - phy_params.recv_delay2 = EU433_RECEIVE_DELAY2; - phy_params.join_channel_mask = EU433_JOIN_CHANNELS; - phy_params.join_accept_delay1 = EU433_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = EU433_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = EU433_MAX_FCNT_GAP; - phy_params.ack_timeout = EU433_ACKTIMEOUT; - phy_params.ack_timeout_rnd = EU433_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = EU433_RX_WND_2_DR; - phy_params.rx_window2_frequency = EU433_RX_WND_2_FREQ; -} - -LoRaPHYEU433::~LoRaPHYEU433() -{ -} diff --git a/features/lorawan/lorastack/phy/LoRaPHYEU433.h b/features/lorawan/lorastack/phy/LoRaPHYEU433.h deleted file mode 100644 index 81417d9..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYEU433.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file LoRaPHYEU433.h - * - * @brief Implements LoRaPHY for European 433 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_EU433_H_ -#define MBED_OS_LORAPHY_EU433_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define EU433_MAX_NB_CHANNELS 16 - -/*! - * LoRaMac maximum number of bands - */ -#define EU433_MAX_NB_BANDS 1 - -#define EU433_CHANNEL_MASK_SIZE 1 - - -class LoRaPHYEU433 : public LoRaPHY { - -public: - - LoRaPHYEU433(); - virtual ~LoRaPHYEU433(); - -private: - /*! - * LoRaMAC channels - */ - channel_params_t channels[EU433_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[EU433_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[EU433_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[EU433_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_EU433_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYEU868.cpp b/features/lorawan/lorastack/phy/LoRaPHYEU868.cpp deleted file mode 100644 index ba1301c..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYEU868.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file LoRaPHYEU868.cpp - * - * @brief Implements LoRaPHY for European 868 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYEU868.h" -#include "lora_phy_ds.h" - -/*! - * Number of default channels - */ -#define EU868_NUMB_DEFAULT_CHANNELS 3 - -/*! - * Number of channels to apply for the CF list - */ -#define EU868_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define EU868_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define EU868_TX_MAX_DATARATE DR_7 - -/*! - * Minimal datarate that can be used by the node - */ -#define EU868_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define EU868_RX_MAX_DATARATE DR_7 - -/*! - * Default datarate used by the node - */ -#define EU868_DEFAULT_DATARATE DR_0 - -#define EU868_DEFAULT_MAX_DATARATE DR_5 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define EU868_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define EU868_MAX_RX1_DR_OFFSET 5 - -/*! - * Default Rx1 receive datarate offset - */ -#define EU868_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define EU868_MIN_TX_POWER TX_POWER_7 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define EU868_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define EU868_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define EU868_DEFAULT_MAX_EIRP 16.0f - -/*! - * Default antenna gain - */ -#define EU868_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define EU868_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define EU868_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define EU868_DUTY_CYCLE_ENABLED 1 - -/*! - * Maximum RX window duration - */ -#define EU868_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define EU868_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define EU868_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define EU868_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define EU868_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define EU868_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define EU868_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define EU868_ACK_TIMEOUT_RND 1000 - -#if ( EU868_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define EU868_RX_WND_2_FREQ 869525000 - -/*! - * Second reception window channel datarate definition. - */ -#define EU868_RX_WND_2_DR DR_0 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND0 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 865000000, 868000000}; // 1.0 % -/*! - * Band 1 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND1 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 868100000, 868600000}; // 1.0 % - -/*! - * Band 2 definition - * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND2 = {1000, EU868_MAX_TX_POWER, 0, 0, 0, 868700000, 869200000}; // 0.1 % - -/*! - * Band 3 definition - * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND3 = {10, EU868_MAX_TX_POWER, 0, 0, 0, 869400000, 869650000}; // 10.0 % - -/*! - * Band 4 definition - * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND4 = {100, EU868_MAX_TX_POWER, 0, 0, 0, 869700000, 870000000}; // 1.0 % - -/*! - * Band 5 definition - It's actually a sub part of Band 2 - * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t EU868_BAND5 = {1000, EU868_MAX_TX_POWER, 0, 0, 0, 863000000, 865000000}; // 0.1 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU868_LC1 = {868100000, 0, { ((DR_5 << 4) | DR_0) }, 1}; - -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU868_LC2 = {868300000, 0, { ((DR_5 << 4) | DR_0) }, 1}; - -/*! - * LoRaMac default channel 3 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t EU868_LC3 = {868500000, 0, { ((DR_5 << 4) | DR_0) }, 1}; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define EU868_JOIN_CHANNELS (uint16_t)(LC(1) | LC(2) | LC(3)) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_EU868[] = {12, 11, 10, 9, 8, 7, 7, 50}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_EU868[] = {125000, 125000, 125000, 125000, 125000, 125000, 250000, 0}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_EU868[] = {51, 51, 51, 115, 242, 242, 242, 242}; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_repeater_EU868[] = {51, 51, 51, 115, 222, 222, 222, 222}; - -LoRaPHYEU868::LoRaPHYEU868() -{ - bands[0] = EU868_BAND0; - bands[1] = EU868_BAND1; - bands[2] = EU868_BAND2; - bands[3] = EU868_BAND3; - bands[4] = EU868_BAND4; - bands[5] = EU868_BAND5; - - // Default Channels are always enabled, rest will be added later - channels[0] = EU868_LC1; - channels[0].band = 1; - channels[1] = EU868_LC2; - channels[1].band = 1; - channels[2] = EU868_LC3; - channels[2].band = 1; - - // Initialize the channels default mask - default_channel_mask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, 1); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = EU868_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = EU868_CHANNEL_MASK_SIZE; - - // set bands for EU868 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = EU868_MAX_NB_BANDS; - - // set bandwidths available in EU868 spectrum - phy_params.bandwidths.table = (void *) bandwidths_EU868; - phy_params.bandwidths.size = 8; - - // set data rates available in EU868 spectrum - phy_params.datarates.table = (void *) datarates_EU868; - phy_params.datarates.size = 8; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_EU868; - phy_params.payloads.size = 8; - phy_params.payloads_with_repeater.table = (void *) max_payloads_repeater_EU868; - phy_params.payloads_with_repeater.size = 8; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = EU868_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = true; - phy_params.fsk_supported = true; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = EU868_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = EU868_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = EU868_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = EU868_TX_MIN_DATARATE; - phy_params.max_tx_datarate = EU868_TX_MAX_DATARATE; - phy_params.min_rx_datarate = EU868_RX_MIN_DATARATE; - phy_params.max_rx_datarate = EU868_RX_MAX_DATARATE; - phy_params.default_datarate = EU868_DEFAULT_DATARATE; - phy_params.default_max_datarate = EU868_DEFAULT_MAX_DATARATE; - phy_params.min_rx1_dr_offset = EU868_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = EU868_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = EU868_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = EU868_MIN_TX_POWER; - phy_params.max_tx_power = EU868_MAX_TX_POWER; - phy_params.default_tx_power = EU868_DEFAULT_TX_POWER; - phy_params.default_max_eirp = EU868_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = EU868_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = EU868_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = EU868_ADR_ACK_DELAY; - phy_params.max_rx_window = EU868_MAX_RX_WINDOW; - phy_params.recv_delay1 = EU868_RECEIVE_DELAY1; - phy_params.recv_delay2 = EU868_RECEIVE_DELAY2; - phy_params.join_channel_mask = EU868_JOIN_CHANNELS; - phy_params.join_accept_delay1 = EU868_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = EU868_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = EU868_MAX_FCNT_GAP; - phy_params.ack_timeout = EU868_ACKTIMEOUT; - phy_params.ack_timeout_rnd = EU868_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = EU868_RX_WND_2_DR; - phy_params.rx_window2_frequency = EU868_RX_WND_2_FREQ; -} - -LoRaPHYEU868::~LoRaPHYEU868() -{ -} - diff --git a/features/lorawan/lorastack/phy/LoRaPHYEU868.h b/features/lorawan/lorastack/phy/LoRaPHYEU868.h deleted file mode 100644 index b3f8de8..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYEU868.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file LoRaPHYEU868.h - * - * @brief Implements LoRaPHY for European 868 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_EU868_H_ -#define MBED_OS_LORAPHY_EU868_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define EU868_MAX_NB_CHANNELS 16 - -/*! - * Maximum number of bands - * - * We have broken down EU-868 MHz BAND 2 into two parts. That's why - * total number of sub-bands is 6. - * from 863 MHz to 865 MHz region is part of BAND 2, however - * we call it Band-5 here. Duty cycle limit is 0.1 % in this sub band. - */ -#define EU868_MAX_NB_BANDS 6 - -#define EU868_CHANNEL_MASK_SIZE 1 - -class LoRaPHYEU868 : public LoRaPHY { - -public: - LoRaPHYEU868(); - virtual ~LoRaPHYEU868(); - -private: - /*! - * LoRaMAC channels - */ - channel_params_t channels[EU868_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[EU868_MAX_NB_BANDS]; - - /*! - * LoRaMac channels mask - */ - uint16_t channel_mask[EU868_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[EU868_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY*/ -#endif /* MBED_OS_LORAPHY_EU868_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp b/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp deleted file mode 100644 index bdcfcc2..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/** - * @file LoRaPHYIN865.cpp - * - * @brief Implements LoRaPHY for Indian 865 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYIN865.h" -#include "lora_phy_ds.h" - - -/*! - * Number of default channels - */ -#define IN865_NUMB_DEFAULT_CHANNELS 3 - -/*! - * Number of channels to apply for the CF list - */ -#define IN865_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define IN865_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define IN865_TX_MAX_DATARATE DR_7 - -/*! - * Minimal datarate that can be used by the node - */ -#define IN865_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define IN865_RX_MAX_DATARATE DR_7 - -/*! - * Default datarate used by the node - */ -#define IN865_DEFAULT_DATARATE DR_0 -#define IN865_DEFAULT_MAX_DATARATE DR_5 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define IN865_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define IN865_MAX_RX1_DR_OFFSET 7 - -/*! - * Default Rx1 receive datarate offset - */ -#define IN865_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define IN865_MIN_TX_POWER TX_POWER_10 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define IN865_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define IN865_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP - */ -#define IN865_DEFAULT_MAX_EIRP 30.0f - -/*! - * Default antenna gain - */ -#define IN865_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define IN865_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define IN865_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define IN865_DUTY_CYCLE_ENABLED 1 - -/*! - * Maximum RX window duration - */ -#define IN865_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define IN865_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define IN865_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define IN865_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define IN865_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define IN865_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define IN865_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define IN865_ACK_TIMEOUT_RND 1000 - -#if ( IN865_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define IN865_RX_WND_2_FREQ 866550000 - -/*! - * Second reception window channel datarate definition. - */ -#define IN865_RX_WND_2_DR DR_2 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t IN865_BAND0 = { 1, IN865_MAX_TX_POWER, 0, 0, 0, 865000000, 867000000 }; // 100.0 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t IN865_LC1 = { 865062500, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t IN865_LC2 = { 865402500, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac default channel 3 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t IN865_LC3 = { 865985000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define IN865_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_IN865[] = { 12, 11, 10, 9, 8, 7, 0, 50 }; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_IN865[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_IN865[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; - -/*! - * Effective datarate offsets for receive window 1. - */ -static const int8_t rx1_dr_offset_IN865[] = { 0, 1, 2, 3, 4, 5, -1, -2 }; - -LoRaPHYIN865::LoRaPHYIN865() -{ - bands[0] = IN865_BAND0; - - // Default Channels are always enabled, rest will be added later - channels[0] = IN865_LC1; - channels[0].band = 0; - channels[1] = IN865_LC2; - channels[1].band = 0; - channels[2] = IN865_LC3; - channels[2].band = 0; - - // Initialize the channels default mask - default_channel_mask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, 1); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = IN865_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = IN865_CHANNEL_MASK_SIZE; - - // set bands for IN865 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = IN865_MAX_NB_BANDS; - - // set bandwidths available in IN865 spectrum - phy_params.bandwidths.table = (void *) bandwidths_IN865; - phy_params.bandwidths.size = 8; - - // set data rates available in IN865 spectrum - phy_params.datarates.table = (void *) datarates_IN865; - phy_params.datarates.size = 8; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_IN865; - phy_params.payloads.size = 8; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater; - phy_params.payloads_with_repeater.size = 8; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = IN865_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = true; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = IN865_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = IN865_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = IN865_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = IN865_TX_MIN_DATARATE; - phy_params.max_tx_datarate = IN865_TX_MAX_DATARATE; - phy_params.min_rx_datarate = IN865_RX_MIN_DATARATE; - phy_params.max_rx_datarate = IN865_RX_MAX_DATARATE; - phy_params.default_datarate = IN865_DEFAULT_DATARATE; - phy_params.default_max_datarate = IN865_DEFAULT_MAX_DATARATE; - phy_params.min_rx1_dr_offset = IN865_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = IN865_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = IN865_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = IN865_MIN_TX_POWER; - phy_params.max_tx_power = IN865_MAX_TX_POWER; - phy_params.default_tx_power = IN865_DEFAULT_TX_POWER; - phy_params.default_max_eirp = IN865_DEFAULT_MAX_EIRP; - phy_params.default_antenna_gain = IN865_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = IN865_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = IN865_ADR_ACK_DELAY; - phy_params.max_rx_window = IN865_MAX_RX_WINDOW; - phy_params.recv_delay1 = IN865_RECEIVE_DELAY1; - phy_params.recv_delay2 = IN865_RECEIVE_DELAY2; - phy_params.join_channel_mask = IN865_JOIN_CHANNELS; - phy_params.join_accept_delay1 = IN865_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = IN865_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = IN865_MAX_FCNT_GAP; - phy_params.ack_timeout = IN865_ACKTIMEOUT; - phy_params.ack_timeout_rnd = IN865_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = IN865_RX_WND_2_DR; - phy_params.rx_window2_frequency = IN865_RX_WND_2_FREQ; -} - -LoRaPHYIN865::~LoRaPHYIN865() -{ -} - -uint8_t LoRaPHYIN865::apply_DR_offset(int8_t dr, int8_t dr_offset) -{ - // Apply offset formula - return MIN(DR_5, MAX(DR_0, dr - rx1_dr_offset_IN865[dr_offset])); -} diff --git a/features/lorawan/lorastack/phy/LoRaPHYIN865.h b/features/lorawan/lorastack/phy/LoRaPHYIN865.h deleted file mode 100644 index d213c2e..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYIN865.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file LoRaPHYIN865.h - * - * @brief Implements LoRaPHY for Indian 865 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_IN865_H_ -#define MBED_OS_LORAPHY_IN865_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define IN865_MAX_NB_CHANNELS 16 - -/*! - * Maximum number of bands - */ -#define IN865_MAX_NB_BANDS 1 - -#define IN865_CHANNEL_MASK_SIZE 1 - - -class LoRaPHYIN865 : public LoRaPHY { - -public: - - LoRaPHYIN865(); - virtual ~LoRaPHYIN865(); - - virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); - -private: - /*! - * LoRaMAC channels - */ - channel_params_t channels[IN865_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[IN865_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[IN865_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[IN865_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY */ -#endif /* MBED_OS_LORAPHY_IN865_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp b/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp deleted file mode 100644 index e5df591..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/** - * @file LoRaPHYKR920.cpp - * - * @brief Implements LoRaPHY for Korean 920 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "LoRaPHYKR920.h" -#include "lora_phy_ds.h" - - -/*! - * Number of default channels - */ -#define KR920_NUMB_DEFAULT_CHANNELS 3 - -/*! - * Number of channels to apply for the CF list - */ -#define KR920_NUMB_CHANNELS_CF_LIST 5 - -/*! - * Minimal datarate that can be used by the node - */ -#define KR920_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define KR920_TX_MAX_DATARATE DR_5 - -/*! - * Minimal datarate that can be used by the node - */ -#define KR920_RX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define KR920_RX_MAX_DATARATE DR_5 - -/*! - * Default datarate used by the node - */ -#define KR920_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define KR920_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define KR920_MAX_RX1_DR_OFFSET 5 - -/*! - * Default Rx1 receive datarate offset - */ -#define KR920_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define KR920_MIN_TX_POWER TX_POWER_7 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define KR920_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define KR920_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max EIRP for frequency 920.9 MHz - 921.9 MHz - */ -#define KR920_DEFAULT_MAX_EIRP_LOW 10.0f - -/*! - * Default Max EIRP for frequency 922.1 MHz - 923.3 MHz - */ -#define KR920_DEFAULT_MAX_EIRP_HIGH 14.0f - -/*! - * Default antenna gain - */ -#define KR920_DEFAULT_ANTENNA_GAIN 2.15f - -/*! - * ADR Ack limit - */ -#define KR920_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define KR920_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define KR920_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define KR920_MAX_RX_WINDOW 4000 - -/*! - * Receive delay 1 - */ -#define KR920_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define KR920_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define KR920_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define KR920_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define KR920_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define KR920_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define KR920_ACK_TIMEOUT_RND 1000 - -#if ( KR920_DEFAULT_DATARATE > DR_5 ) -#error "A default DR higher than DR_5 may lead to connectivity loss." -#endif - -/*! - * Second reception window channel frequency definition. - */ -#define KR920_RX_WND_2_FREQ 921900000 - -/*! - * Second reception window channel datarate definition. - */ -#define KR920_RX_WND_2_DR DR_0 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t KR920_BAND0 = { 1, KR920_MAX_TX_POWER, 0, 0, 0 }; // 100.0 % - -/*! - * LoRaMac default channel 1 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t KR920_LC1 = { 922100000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac default channel 2 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t KR920_LC2 = { 922300000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac default channel 3 - * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } - */ -static const channel_params_t KR920_LC3 = { 922500000, 0, { ((DR_5 << 4) | DR_0) }, 0 }; - -/*! - * LoRaMac channels which are allowed for the join procedure - */ -#define KR920_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) - -/*! - * RSSI threshold for a free channel [dBm] - */ -#define KR920_RSSI_FREE_TH -65 - -/*! - * Specifies the time the node performs a carrier sense - */ -#define KR920_CARRIER_SENSE_TIME 6 - -/*! - * Data rates table definition - */ -static const uint8_t datarates_KR920[] = { 12, 11, 10, 9, 8, 7 }; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_KR920[] = { 125000, 125000, 125000, 125000, 125000, 125000 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with and without a repeater. - */ -static const uint8_t max_payloads_KR920[] = { 51, 51, 51, 115, 242, 242 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_KR920[] = { 51, 51, 51, 115, 222, 222 }; - -LoRaPHYKR920::LoRaPHYKR920() -{ - bands[0] = KR920_BAND0; - - // Channels - channels[0] = KR920_LC1; - channels[0].band = 0; - channels[1] = KR920_LC2; - channels[1].band = 0; - channels[2] = KR920_LC3; - channels[2].band = 0; - - // Initialize the channels default mask - default_channel_mask[0] = LC(1) + LC(2) + LC(3); - // Update the channels mask - copy_channel_mask(channel_mask, default_channel_mask, KR920_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = KR920_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = KR920_CHANNEL_MASK_SIZE; - - // set bands for KR920 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = KR920_MAX_NB_BANDS; - - // set bandwidths available in KR920 spectrum - phy_params.bandwidths.table = (void *) bandwidths_KR920; - phy_params.bandwidths.size = 6; - - // set data rates available in KR920 spectrum - phy_params.datarates.table = (void *) datarates_KR920; - phy_params.datarates.size = 6; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_KR920; - phy_params.payloads.size = 6; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_KR920; - phy_params.payloads_with_repeater.size = 6; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = KR920_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = false; - phy_params.cflist_supported = true; - phy_params.dl_channel_req_supported = true; - phy_params.custom_channelplans_supported = true; - phy_params.default_channel_cnt = KR920_NUMB_DEFAULT_CHANNELS; - phy_params.max_channel_cnt = KR920_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = KR920_NUMB_CHANNELS_CF_LIST; - phy_params.min_tx_datarate = KR920_TX_MIN_DATARATE; - phy_params.max_tx_datarate = KR920_TX_MAX_DATARATE; - phy_params.min_rx_datarate = KR920_RX_MIN_DATARATE; - phy_params.max_rx_datarate = KR920_RX_MAX_DATARATE; - phy_params.default_datarate = KR920_DEFAULT_DATARATE; - phy_params.default_max_datarate = KR920_TX_MAX_DATARATE; - phy_params.min_rx1_dr_offset = KR920_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = KR920_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = KR920_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = KR920_MIN_TX_POWER; - phy_params.max_tx_power = KR920_MAX_TX_POWER; - phy_params.default_tx_power = KR920_DEFAULT_TX_POWER; - phy_params.default_max_eirp = KR920_DEFAULT_MAX_EIRP_HIGH; - phy_params.default_antenna_gain = KR920_DEFAULT_ANTENNA_GAIN; - phy_params.adr_ack_limit = KR920_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = KR920_ADR_ACK_DELAY; - phy_params.max_rx_window = KR920_MAX_RX_WINDOW; - phy_params.recv_delay1 = KR920_RECEIVE_DELAY1; - phy_params.recv_delay2 = KR920_RECEIVE_DELAY2; - phy_params.join_channel_mask = KR920_JOIN_CHANNELS; - phy_params.join_accept_delay1 = KR920_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = KR920_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = KR920_MAX_FCNT_GAP; - phy_params.ack_timeout = KR920_ACKTIMEOUT; - phy_params.ack_timeout_rnd = KR920_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = KR920_RX_WND_2_DR; - phy_params.rx_window2_frequency = KR920_RX_WND_2_FREQ; -} - -LoRaPHYKR920::~LoRaPHYKR920() -{ -} - -int8_t LoRaPHYKR920::get_max_eirp(uint32_t freq) -{ - if (freq >= 922100000) {// Limit to 14dBm - return KR920_DEFAULT_MAX_EIRP_HIGH; - } - - // Limit to 10dBm - return KR920_DEFAULT_MAX_EIRP_LOW; -} - - -bool LoRaPHYKR920::verify_frequency_for_band(uint32_t freq, uint8_t band) const -{ - uint32_t tmp_freq = freq; - - _radio->lock(); - - if (_radio->check_rf_frequency(tmp_freq) == false) { - _radio->unlock(); - return false; - } - - _radio->unlock(); - - // Verify if the frequency is valid. The frequency must be in a specified - // range and can be set to specific values. - if ((tmp_freq >= 920900000) && (tmp_freq <= 923300000)) { - // Range ok, check for specific value - tmp_freq -= 920900000; - if ((tmp_freq % 200000) == 0) { - return true; - } - } - - return false; -} - -bool LoRaPHYKR920::tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa) -{ - int8_t phy_dr = datarates_KR920[config->datarate]; - - if (config->tx_power > bands[channels[config->channel].band].max_tx_pwr) { - config->tx_power = bands[channels[config->channel].band].max_tx_pwr; - } - - uint32_t bandwidth = get_bandwidth(config->datarate); - float max_eirp = get_max_eirp(channels[config->channel].frequency); - int8_t phy_tx_power = 0; - - // Take the minimum between the max_eirp and txConfig->MaxEirp. - // The value of txConfig->MaxEirp could have changed during runtime, e.g. due to a MAC command. - max_eirp = MIN(config->max_eirp, max_eirp); - - // Calculate physical TX power - phy_tx_power = compute_tx_power(config->tx_power, max_eirp, config->antenna_gain); - - // Setup the radio frequency - _radio->lock(); - - _radio->set_channel(channels[config->channel].frequency); - - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, - false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); - // Get the time-on-air of the next tx frame - *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); - - _radio->unlock(); - - *tx_power = config->tx_power; - return true; -} - -lorawan_status_t LoRaPHYKR920::set_next_channel(channel_selection_params_t *params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeoff) -{ - uint8_t next_channel_idx = 0; - uint8_t nb_enabled_channels = 0; - uint8_t delay_tx = 0; - uint8_t enabled_channels[KR920_MAX_NB_CHANNELS] = {0}; - lorawan_time_t nextTxDelay = 0; - - if (num_active_channels(channel_mask, 0, 1) == 0) { - // Reactivate default channels - channel_mask[0] |= LC(1) + LC(2) + LC(3); - } - - if (params->aggregate_timeoff <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeoff = 0; - - // Update bands Time OFF - nextTxDelay = update_band_timeoff(params->joined, params->dc_enabled, - bands, KR920_MAX_NB_BANDS); - - // Search how many channels are enabled - nb_enabled_channels = enabled_channel_count(params->current_datarate, - channel_mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - nextTxDelay = params->aggregate_timeoff - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); - } - - if (nb_enabled_channels > 0) { - - for (uint8_t i = 0, j = get_random(0, nb_enabled_channels - 1); - i < KR920_MAX_NB_CHANNELS; i++) { - next_channel_idx = enabled_channels[j]; - j = (j + 1) % nb_enabled_channels; - - // Perform carrier sense for KR920_CARRIER_SENSE_TIME - // If the channel is free, we can stop the LBT mechanism - _radio->lock(); - - if (_radio->perform_carrier_sense(MODEM_LORA, - channels[next_channel_idx].frequency, - KR920_RSSI_FREE_TH, - KR920_CARRIER_SENSE_TIME) == true) { - // Free channel found - *channel = next_channel_idx; - *time = 0; - _radio->unlock(); - return LORAWAN_STATUS_OK; - } - - _radio->unlock(); - } - - return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; - - } else { - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = nextTxDelay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - // Datarate not supported by any channel, restore defaults - channel_mask[0] |= LC(1) + LC(2) + LC(3); - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; - } -} - -void LoRaPHYKR920::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) -{ - (void)given_frequency; - - if (params->tx_power > bands[channels[params->channel].band].max_tx_pwr) { - params->tx_power = bands[channels[params->channel].band].max_tx_pwr; - } - - float max_eirp = get_max_eirp(channels[params->channel].frequency); - int8_t phy_tx_power = 0; - uint32_t frequency = channels[params->channel].frequency; - - // Take the minimum between the max_eirp and params->max_eirp. - // The value of params->max_eirp could have changed during runtime, - // e.g. due to a MAC command. - max_eirp = MIN(params->max_eirp, max_eirp); - - // Calculate physical TX power - phy_tx_power = compute_tx_power(params->tx_power, max_eirp, params->antenna_gain); - - _radio->lock(); - _radio->set_tx_continuous_wave(frequency, phy_tx_power, params->timeout); - _radio->unlock(); -} - diff --git a/features/lorawan/lorastack/phy/LoRaPHYKR920.h b/features/lorawan/lorastack/phy/LoRaPHYKR920.h deleted file mode 100644 index ae7af46..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYKR920.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file LoRaPHYKR920.h - * - * @brief Implements LoRaPHY for Korean 920 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHY_KR920_H_ -#define MBED_OS_LORAPHY_KR920_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define KR920_MAX_NB_CHANNELS 16 - -/*! - * Maximum number of bands - */ -#define KR920_MAX_NB_BANDS 1 - -#define KR920_CHANNEL_MASK_SIZE 1 - - -class LoRaPHYKR920 : public LoRaPHY { - -public: - - LoRaPHYKR920(); - virtual ~LoRaPHYKR920(); - - virtual bool verify_frequency_for_band(uint32_t freq, uint8_t band) const; - - virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, uint8_t *channel, - lorawan_time_t *time, - lorawan_time_t *aggregate_timeOff); - - virtual void set_tx_cont_mode(cw_mode_params_t *continuousWave, - uint32_t frequency = 0); - - -private: - - int8_t get_max_eirp(uint32_t freq); - - /** - * LoRaMAC channels - */ - channel_params_t channels[KR920_MAX_NB_CHANNELS]; - - /** - * LoRaMac bands - */ - band_t bands[KR920_MAX_NB_BANDS]; - - /** - * LoRaMac channel mask - */ - uint16_t channel_mask[KR920_CHANNEL_MASK_SIZE]; - - /** - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[KR920_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY */ -#endif // MBED_OS_LORAPHY_KR920_H_ - diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp deleted file mode 100644 index 9882b5e..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/** - * @file LoRaPHUS915.cpp - * - * @brief Implements LoRaPHY for US 915 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include -#include "LoRaPHYUS915.h" -#include "lora_phy_ds.h" - - -/*! - * Minimal datarate that can be used by the node - */ -#define US915_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define US915_TX_MAX_DATARATE DR_4 - -/*! - * Minimal datarate that can be used by the node - */ -#define US915_RX_MIN_DATARATE DR_8 - -/*! - * Maximal datarate that can be used by the node - */ -#define US915_RX_MAX_DATARATE DR_13 - -/*! - * Default datarate used by the node - */ -#define US915_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define US915_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define US915_MAX_RX1_DR_OFFSET 3 - -/*! - * Default Rx1 receive datarate offset - */ -#define US915_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define US915_MIN_TX_POWER TX_POWER_10 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define US915_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define US915_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max ERP - */ -#define US915_DEFAULT_MAX_ERP 30.0f - -/*! - * ADR Ack limit - */ -#define US915_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define US915_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define US915_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define US915_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define US915_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define US915_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define US915_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define US915_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define US915_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define US915_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define US915_ACK_TIMEOUT_RND 1000 - -/*! - * Second reception window channel frequency definition. - */ -#define US915_RX_WND_2_FREQ 923300000 - -/*! - * Second reception window channel datarate definition. - */ -#define US915_RX_WND_2_DR DR_8 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t US915_BAND0 = { 1, US915_MAX_TX_POWER, 0, 0, 0 }; // 100.0 % - -/*! - * Defines the first channel for RX window 1 for US band - */ -#define US915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) - -/*! - * Defines the last channel for RX window 1 for US band - */ -#define US915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) - -/*! - * Defines the step width of the channels for RX window 1 - */ -#define US915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_US915[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0}; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_US915[] = {125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0}; - -/*! - * Up/Down link data rates offset definition - */ -static const int8_t datarate_offsets_US915[5][4] = { - { DR_10, DR_9, DR_8, DR_8 }, // DR_0 - { DR_11, DR_10, DR_9, DR_8 }, // DR_1 - { DR_12, DR_11, DR_10, DR_9 }, // DR_2 - { DR_13, DR_12, DR_11, DR_10 }, // DR_3 - { DR_13, DR_13, DR_12, DR_11 }, // DR_4 -}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0}; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; - -static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; -static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; - -LoRaPHYUS915::LoRaPHYUS915() -{ - bands[0] = US915_BAND0; - - // Channels - // 125 kHz channels - Upstream - for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++) { - channels[i].frequency = 902300000 + i * 200000; - channels[i].dr_range.value = (DR_3 << 4) | DR_0; - channels[i].band = 0; - } - // 500 kHz channels - Upstream - for (uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++) { - channels[i].frequency = 903000000 + (i - (US915_MAX_NB_CHANNELS - 8)) * 1600000; - channels[i].dr_range.value = (DR_4 << 4) | DR_4; - channels[i].band = 0; - } - - // Fill-up default channel mask and apply FSB mask too - fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, - default_channel_mask, US915_CHANNEL_MASK_SIZE); - - memset(channel_mask, 0, sizeof(channel_mask)); - memset(current_channel_mask, 0, sizeof(current_channel_mask)); - - // Copy channels default mask - copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); - - // current channel masks keep track of the - // channels previously used, i.e., which channels should be avoided in - // next transmission - copy_channel_mask(current_channel_mask, channel_mask, US915_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = US915_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = US915_CHANNEL_MASK_SIZE; - - // set bands for US915 spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = US915_MAX_NB_BANDS; - - // set bandwidths available in US915 spectrum - phy_params.bandwidths.table = (void *) bandwidths_US915; - phy_params.bandwidths.size = 16; - - // set data rates available in US915 spectrum - phy_params.datarates.table = (void *) datarates_US915; - phy_params.datarates.size = 16; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_US915; - phy_params.payloads.size = 16; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_US915; - phy_params.payloads_with_repeater.size = 16; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = US915_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = false; - phy_params.cflist_supported = false; - phy_params.dl_channel_req_supported = false; - phy_params.custom_channelplans_supported = false; - phy_params.default_channel_cnt = US915_MAX_NB_CHANNELS; - phy_params.max_channel_cnt = US915_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = 0; - phy_params.min_tx_datarate = US915_TX_MIN_DATARATE; - phy_params.max_tx_datarate = US915_TX_MAX_DATARATE; - phy_params.min_rx_datarate = US915_RX_MIN_DATARATE; - phy_params.max_rx_datarate = US915_RX_MAX_DATARATE; - phy_params.default_datarate = US915_DEFAULT_DATARATE; - phy_params.default_max_datarate = US915_TX_MAX_DATARATE; - phy_params.min_rx1_dr_offset = US915_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = US915_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = US915_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = US915_MIN_TX_POWER; - phy_params.max_tx_power = US915_MAX_TX_POWER; - phy_params.default_tx_power = US915_DEFAULT_TX_POWER; - phy_params.default_max_eirp = 0; - phy_params.default_antenna_gain = 0; - phy_params.adr_ack_limit = US915_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = US915_ADR_ACK_DELAY; - phy_params.max_rx_window = US915_MAX_RX_WINDOW; - phy_params.recv_delay1 = US915_RECEIVE_DELAY1; - phy_params.recv_delay2 = US915_RECEIVE_DELAY2; - - phy_params.join_accept_delay1 = US915_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = US915_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = US915_MAX_FCNT_GAP; - phy_params.ack_timeout = US915_ACKTIMEOUT; - phy_params.ack_timeout_rnd = US915_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = US915_RX_WND_2_DR; - phy_params.rx_window2_frequency = US915_RX_WND_2_FREQ; -} - -LoRaPHYUS915::~LoRaPHYUS915() -{ -} - -int8_t LoRaPHYUS915::limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, - int8_t datarate) -{ - int8_t tx_power_out = tx_power; - - // Limit tx power to the band max - tx_power_out = MAX(tx_power, max_band_tx_power); - - if (datarate == DR_4) { - // Limit tx power to max 26dBm - tx_power_out = MAX(tx_power, TX_POWER_2); - } else { - - if (num_active_channels(channel_mask, 0, 4) < 50) { - // Limit tx power to max 21dBm - tx_power_out = MAX(tx_power, TX_POWER_5); - } - } - - return tx_power_out; -} - -void LoRaPHYUS915::restore_default_channels() -{ - // Copy channels default mask - copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); - - // Update running channel mask - intersect_channel_mask(channel_mask, current_channel_mask, US915_CHANNEL_MASK_SIZE); -} - -bool LoRaPHYUS915::rx_config(rx_config_params_t *config) -{ - int8_t dr = config->datarate; - uint8_t max_payload = 0; - int8_t phy_dr = 0; - uint32_t frequency = config->frequency; - - _radio->lock(); - - if (_radio->get_status() != RF_IDLE) { - - _radio->unlock(); - return false; - - } - - _radio->unlock(); - - // For US915 spectrum, we have 8 Downstream channels, MAC would have - // selected a channel randomly from 72 Upstream channels, that index is - // passed in rx_config_params_t. Based on that channel index, we choose the - // frequency for first RX slot - if (config->rx_slot == RX_SLOT_WIN_1) { - // Apply window 1 frequency - frequency = US915_FIRST_RX1_CHANNEL + (config->channel % 8) * US915_STEPWIDTH_RX1_CHANNEL; - // Caller may print the frequency to log so update it to match actual frequency - config->frequency = frequency; - } - - // Read the physical datarate from the datarates table - phy_dr = datarates_US915[dr]; - - _radio->lock(); - - _radio->set_channel(frequency); - - // Radio configuration - _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, - MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, - config->window_timeout, false, 0, false, 0, 0, true, - config->is_rx_continuous); - _radio->unlock(); - - if (config->is_repeater_supported == true) { - - max_payload = max_payloads_with_repeater_US915[dr]; - - } else { - - max_payload = max_payloads_US915[dr]; - - } - - _radio->lock(); - - _radio->set_max_payload_length(MODEM_LORA, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - - _radio->unlock(); - - return true; -} - -bool LoRaPHYUS915::tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa) -{ - int8_t phy_dr = datarates_US915[config->datarate]; - int8_t tx_power_limited = limit_tx_power(config->tx_power, - bands[channels[config->channel].band].max_tx_pwr, - config->datarate); - - uint32_t bandwidth = get_bandwidth(config->datarate); - int8_t phy_tx_power = 0; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(tx_power_limited, US915_DEFAULT_MAX_ERP, 0); - - _radio->lock(); - - _radio->set_channel(channels[config->channel].frequency); - - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, - MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, - false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); - - // Get the time-on-air of the next tx frame - *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); - - _radio->unlock(); - - *tx_power = tx_power_limited; - - return true; -} - -uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t *params, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, uint8_t *nb_bytes_parsed) -{ - uint8_t status = 0x07; - - link_adr_params_t adr_settings; - uint8_t next_idx = 0; - uint8_t bytes_processed = 0; - uint16_t temp_channel_masks[US915_CHANNEL_MASK_SIZE] = {0, 0, 0, 0, 0}; - - verify_adr_params_t verify_params; - - // Initialize local copy of channels mask - copy_channel_mask(temp_channel_masks, channel_mask, US915_CHANNEL_MASK_SIZE); - - while (bytes_processed < params->payload_size && - params->payload[bytes_processed] == SRV_MAC_LINK_ADR_REQ) { - next_idx = parse_link_ADR_req(&(params->payload[bytes_processed]), - params->payload_size - bytes_processed, - &adr_settings); - - if (next_idx == 0) { - bytes_processed = 0; - // break loop, malformed packet - break; - } - - // Update bytes processed - bytes_processed += next_idx; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (adr_settings.ch_mask_ctrl == 6) { - - // Enable all 125 kHz channels - fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, - US915_CHANNEL_MASK_SIZE - 1); - - // Apply chMask to channels 64 to 71 - temp_channel_masks[4] = adr_settings.channel_mask; - - } else if (adr_settings.ch_mask_ctrl == 7) { - - // Disable all 125 kHz channels - fill_channel_mask_with_value(temp_channel_masks, 0x0000, - US915_CHANNEL_MASK_SIZE - 1); - - // Apply chMask to channels 64 to 71 - temp_channel_masks[4] = adr_settings.channel_mask; - - } else if (adr_settings.ch_mask_ctrl == 5) { - // RFU - status &= 0xFE; // Channel mask KO - - } else { - temp_channel_masks[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; - } - } - - if (bytes_processed == 0) { - *nb_bytes_parsed = 0; - return status; - } - - // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels - if ((adr_settings.datarate < DR_4) && - (num_active_channels(temp_channel_masks, 0, 4) < 2)) { - - status &= 0xFE; // Channel mask KO - - } - - verify_params.status = status; - verify_params.adr_enabled = params->adr_enabled; - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; - verify_params.current_datarate = params->current_datarate; - verify_params.current_tx_power = params->current_tx_power; - verify_params.current_nb_rep = params->current_nb_trans; - verify_params.channel_mask = temp_channel_masks; - - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); - - // Update channelsMask if everything is correct - if (status == 0x07) { - // Copy Mask - copy_channel_mask(channel_mask, temp_channel_masks, US915_CHANNEL_MASK_SIZE); - - // update running channel mask - intersect_channel_mask(channel_mask, current_channel_mask, - US915_CHANNEL_MASK_SIZE); - } - - // Update status variables - *dr_out = adr_settings.datarate; - *tx_power_out = adr_settings.tx_power; - *nb_rep_out = adr_settings.nb_rep; - *nb_bytes_parsed = bytes_processed; - - return status; -} - -uint8_t LoRaPHYUS915::accept_rx_param_setup_req(rx_param_setup_req_t *params) -{ - uint8_t status = 0x07; - uint32_t freq = params->frequency; - - // Verify radio frequency - if ((_radio->check_rf_frequency(freq) == false) - || (freq < US915_FIRST_RX1_CHANNEL) - || (freq > US915_LAST_RX1_CHANNEL) - || (((freq - (uint32_t) US915_FIRST_RX1_CHANNEL) % (uint32_t) US915_STEPWIDTH_RX1_CHANNEL) != 0)) { - - status &= 0xFE; // Channel frequency KO - - } - - // Verify datarate - if (val_in_range(params->datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE) == 0) { - - status &= 0xFD; // Datarate KO - - } - - if ((val_in_range(params->datarate, DR_5, DR_7)) || (params->datarate > DR_13)) { - - status &= 0xFD; // Datarate KO - - } - - // Verify datarate offset - if (val_in_range(params->dr_offset, US915_MIN_RX1_DR_OFFSET, US915_MAX_RX1_DR_OFFSET) == 0) { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; -} - -int8_t LoRaPHYUS915::get_alternate_DR(uint8_t nb_trials) -{ - int8_t datarate = 0; - - if ((nb_trials & 0x01) == 0x01) { - datarate = DR_4; - } else { - datarate = DR_0; - } - - return datarate; -} - -lorawan_status_t LoRaPHYUS915::set_next_channel(channel_selection_params_t *params, - uint8_t *channel, lorawan_time_t *time, - lorawan_time_t *aggregate_timeOff) -{ - uint8_t nb_enabled_channels = 0; - uint8_t delay_tx = 0; - uint8_t enabled_channels[US915_MAX_NB_CHANNELS] = {0}; - lorawan_time_t next_tx_delay = 0; - - // Count 125kHz channels - if (num_active_channels(current_channel_mask, 0, 4) == 0) { - // If none of the 125 kHz Upstream channel found, - // Reactivate default channels - copy_channel_mask(current_channel_mask, channel_mask, 4); - } - - // Update the 500 kHz channels in the running mask - if ((params->current_datarate >= DR_4) - && (current_channel_mask[4] & 0x00FF) == 0) { - current_channel_mask[4] = channel_mask[4]; - } - - if (params->aggregate_timeoff <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeOff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(params->joined, params->dc_enabled, bands, US915_MAX_NB_BANDS); - - // Search how many channels are enabled - nb_enabled_channels = enabled_channel_count(params->current_datarate, - current_channel_mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = params->aggregate_timeoff - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); - } - - if (nb_enabled_channels > 0) { - // We found a valid channel - *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; - // Disable the channel in the mask - disable_channel(current_channel_mask, *channel, US915_MAX_NB_CHANNELS); - - *time = 0; - return LORAWAN_STATUS_OK; - - } else { - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - // Datarate not supported by any channel - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; - } -} - -void LoRaPHYUS915::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency) -{ - (void)given_frequency; - - int8_t tx_power_limited = limit_tx_power(params->tx_power, - bands[channels[params->channel].band].max_tx_pwr, - params->datarate); - int8_t phyTxPower = 0; - uint32_t frequency = channels[params->channel].frequency; - - // Calculate physical TX power - phyTxPower = compute_tx_power(tx_power_limited, US915_DEFAULT_MAX_ERP, 0); - - _radio->lock(); - - _radio->set_tx_continuous_wave(frequency, phyTxPower, params->timeout); - - _radio->unlock(); -} - -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 deleted file mode 100644 index 1896c4a..0000000 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file LoRaPHYUS915.h - * - * @brief Implements LoRaPHY for US 915 MHz band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORAPHYUS_915_H_ -#define MBED_OS_LORAPHYUS_915_H_ - -#if !(DOXYGEN_ONLY) - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define US915_MAX_NB_CHANNELS 72 - -/*! - * LoRaMac maximum number of bands - */ -#define US915_MAX_NB_BANDS 1 - -#define US915_CHANNEL_MASK_SIZE 5 - - -class LoRaPHYUS915 : public LoRaPHY { - -public: - - LoRaPHYUS915(); - virtual ~LoRaPHYUS915(); - - virtual void restore_default_channels(); - - virtual bool rx_config(rx_config_params_t *config); - - virtual bool tx_config(tx_config_params_t *config, int8_t *tx_power, - lorawan_time_t *tx_toa); - - virtual uint8_t link_ADR_request(adr_req_params_t *params, - int8_t *dr_out, int8_t *tx_power_out, - uint8_t *nb_rep_out, - uint8_t *nb_bytes_parsed); - - virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t *params); - - virtual int8_t get_alternate_DR(uint8_t nb_trials); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t *params, uint8_t *channel, - lorawan_time_t *time, lorawan_time_t *aggregate_timeOff); - - virtual void set_tx_cont_mode(cw_mode_params_t *continuousWave, - uint32_t frequency = 0); - - 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); - - int8_t limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, - int8_t datarate); - - /*! - * LoRaMAC channels - */ - channel_params_t channels[US915_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[US915_MAX_NB_BANDS]; - - /*! - * LoRaMac channel mask - */ - uint16_t channel_mask[US915_CHANNEL_MASK_SIZE]; - - /*! - * Previously used channel mask - */ - uint16_t current_channel_mask[US915_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[US915_CHANNEL_MASK_SIZE]; -}; - -#endif /* DOXYGEN_ONLY */ -#endif /* MBED_OS_LORAPHY_US915_H_ */ diff --git a/features/lorawan/lorastack/phy/lora_phy_ds.h b/features/lorawan/lorastack/phy/lora_phy_ds.h deleted file mode 100644 index 4bd5cff..0000000 --- a/features/lorawan/lorastack/phy/lora_phy_ds.h +++ /dev/null @@ -1,565 +0,0 @@ -/** - * @file lora_phy_ds.h - * - * @brief Data structures relating to PHY layer - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_OS_LORA_PHY_DATASTRUCTURES_ -#define MBED_OS_LORA_PHY_DATASTRUCTURES_ - -#include "system/lorawan_data_structures.h" - -/*! - * \brief Returns the minimum value between a and b. - * - * \param [in] a The first value. - * \param [in] b The second value. - * \retval minValue The minimum value. - */ -#ifndef MIN -#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) -#endif - -/*! - * \brief Returns the maximum value between a and b - * - * \param [in] a The first value. - * \param [in] b The second value. - * \retval maxValue The maximum value. - */ -#ifndef MAX -#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) -#endif - -/** - * LoRaMac maximum number of channels. - */ -#define LORA_MAX_NB_CHANNELS 16 - -/*! - * Macro to compute bit of a channel index. - */ -#define LC( channelIndex ) ( uint16_t )( 1 << ( channelIndex - 1 ) ) - - - - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - * AU915 | Max EIRP - * CN470 | Max EIRP - * CN779 | Max EIRP - * EU433 | Max EIRP - * EU868 | Max EIRP - * IN865 | Max EIRP - * KR920 | Max EIRP - * US915 | Max ERP - * US915_HYBRID | Max ERP - */ -#define TX_POWER_0 0 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 2 - * AU915 | Max EIRP - 2 - * CN470 | Max EIRP - 2 - * CN779 | Max EIRP - 2 - * EU433 | Max EIRP - 2 - * EU868 | Max EIRP - 2 - * IN865 | Max EIRP - 2 - * KR920 | Max EIRP - 2 - * US915 | Max ERP - 2 - * US915_HYBRID | Max ERP - 2 - */ -#define TX_POWER_1 1 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 4 - * AU915 | Max EIRP - 4 - * CN470 | Max EIRP - 4 - * CN779 | Max EIRP - 4 - * EU433 | Max EIRP - 4 - * EU868 | Max EIRP - 4 - * IN865 | Max EIRP - 4 - * KR920 | Max EIRP - 4 - * US915 | Max ERP - 4 - * US915_HYBRID | Max ERP - 4 - */ -#define TX_POWER_2 2 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 6 - * AU915 | Max EIRP - 6 - * CN470 | Max EIRP - 6 - * CN779 | Max EIRP - 6 - * EU433 | Max EIRP - 6 - * EU868 | Max EIRP - 6 - * IN865 | Max EIRP - 6 - * KR920 | Max EIRP - 6 - * US915 | Max ERP - 6 - * US915_HYBRID | Max ERP - 6 - */ -#define TX_POWER_3 3 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 8 - * AU915 | Max EIRP - 8 - * CN470 | Max EIRP - 8 - * CN779 | Max EIRP - 8 - * EU433 | Max EIRP - 8 - * EU868 | Max EIRP - 8 - * IN865 | Max EIRP - 8 - * KR920 | Max EIRP - 8 - * US915 | Max ERP - 8 - * US915_HYBRID | Max ERP - 8 - */ -#define TX_POWER_4 4 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 10 - * AU915 | Max EIRP - 10 - * CN470 | Max EIRP - 10 - * CN779 | Max EIRP - 10 - * EU433 | Max EIRP - 10 - * EU868 | Max EIRP - 10 - * IN865 | Max EIRP - 10 - * KR920 | Max EIRP - 10 - * US915 | Max ERP - 10 - * US915_HYBRID | Max ERP - 10 - */ -#define TX_POWER_5 5 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 12 - * AU915 | Max EIRP - 12 - * CN470 | Max EIRP - 12 - * CN779 | - - * EU433 | - - * EU868 | Max EIRP - 12 - * IN865 | Max EIRP - 12 - * KR920 | Max EIRP - 12 - * US915 | Max ERP - 12 - * US915_HYBRID | Max ERP - 12 - */ -#define TX_POWER_6 6 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | Max EIRP - 14 - * AU915 | Max EIRP - 14 - * CN470 | Max EIRP - 14 - * CN779 | - - * EU433 | - - * EU868 | Max EIRP - 14 - * IN865 | Max EIRP - 14 - * KR920 | Max EIRP - 14 - * US915 | Max ERP - 14 - * US915_HYBRID | Max ERP - 14 - */ -#define TX_POWER_7 7 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | - - * AU915 | Max EIRP - 16 - * CN470 | - - * CN779 | - - * EU433 | - - * EU868 | - - * IN865 | Max EIRP - 16 - * KR920 | - - * US915 | Max ERP - 16 - * US915_HYBRID | Max ERP -16 - */ -#define TX_POWER_8 8 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | - - * AU915 | Max EIRP - 18 - * CN470 | - - * CN779 | - - * EU433 | - - * EU868 | - - * IN865 | Max EIRP - 18 - * KR920 | - - * US915 | Max ERP - 16 - * US915_HYBRID | Max ERP - 16 - */ -#define TX_POWER_9 9 - -/*! - * Region | dBM - * ------------ | :-----: - * AS923 | - - * AU915 | Max EIRP - 20 - * CN470 | - - * CN779 | - - * EU433 | - - * EU868 | - - * IN865 | Max EIRP - 20 - * KR920 | - - * US915 | Max ERP - 10 - * US915_HYBRID | Max ERP - 10 - */ -#define TX_POWER_10 10 - -/*! - * RFU - */ -#define TX_POWER_11 11 - -/*! - * RFU - */ -#define TX_POWER_12 12 - -/*! - * RFU - */ -#define TX_POWER_13 13 - -/*! - * RFU - */ -#define TX_POWER_14 14 - -/*! - * RFU - */ -#define TX_POWER_15 15 - -/** - * TX configuration parameters. - */ -typedef struct { - /** - * The TX channel. - */ - uint8_t channel; - /** - * The TX datarate. - */ - int8_t datarate; - /** - * The TX power. - */ - int8_t tx_power; - /** - * The Max EIRP, if applicable. - */ - float max_eirp; - /** - * The antenna gain, if applicable. - */ - float antenna_gain; - /** - * The frame length to set up. - */ - uint16_t pkt_len; -} tx_config_params_t; - -/** - * This structure contains parameters for ADR request coming from - * network server. - */ -typedef struct { - /*! - * A pointer to the payload containing the MAC commands. - */ - const uint8_t *payload; - /*! - * The size of the payload. - */ - uint8_t payload_size; - /*! - * The uplink dwell time. - */ - uint8_t ul_dwell_time; - /*! - * Set to true, if ADR is enabled. - */ - bool adr_enabled; - /*! - * The current datarate. - */ - int8_t current_datarate; - /*! - * The current TX power. - */ - int8_t current_tx_power; - /*! - * The current number of repetitions for obtaining a QOS level set by - * NS (applicable only to unconfirmed messages). - */ - uint8_t current_nb_trans; -} adr_req_params_t; - -/** - * Structure containing data for local ADR settings - */ -typedef struct link_adr_params_s { - /** - * The number of repetitions. - */ - uint8_t nb_rep; - /** - * Datarate. - */ - int8_t datarate; - /** - * TX power. - */ - int8_t tx_power; - /** - * Channels mask control field. - */ - uint8_t ch_mask_ctrl; - /** - * Channels mask field. - */ - uint16_t channel_mask; -} link_adr_params_t; - -/** - * Structure used to store ADR values received from network - * for verification (legality) purposes. - */ -typedef struct verify_adr_params_s { - /*! - * The current status of the AdrLinkRequest. - */ - uint8_t status; - /*! - * Set to true, if ADR is enabled. - */ - bool adr_enabled; - /*! - * The datarate the AdrLinkRequest wants to set. - */ - int8_t datarate; - /*! - * The TX power the AdrLinkRequest wants to set. - */ - int8_t tx_power; - /*! - * The number of repetitions the AdrLinkRequest wants to set. - */ - uint8_t nb_rep; - /*! - * The current datarate the node is using. - */ - int8_t current_datarate; - /*! - * The current TX power the node is using. - */ - int8_t current_tx_power; - /*! - * The current number of repetitions the node is using. - */ - int8_t current_nb_rep; - - /*! - * A pointer to the first element of the channels mask. - */ - uint16_t *channel_mask; -} verify_adr_params_t; - -/** - * Contains rx parameter setup request coming from - * network server. - */ -typedef struct rx_param_setup_req_s { - /** - * The datarate to set up. - */ - int8_t datarate; - /** - * The datarate offset. - */ - int8_t dr_offset; - /** - * The frequency to set up. - */ - uint32_t frequency; -} rx_param_setup_req_t; - -/** - * The parameter structure for the function RegionNextChannel. - */ -typedef struct channel_selection_params_s { - /** - * The aggregated time-off time. - */ - lorawan_time_t aggregate_timeoff; - /** - * The time of the last aggregated TX. - */ - lorawan_time_t last_aggregate_tx_time; - /** - * The current datarate. - */ - int8_t current_datarate; - /** - * Set to true, if the node has already joined a network, otherwise false. - */ - bool joined; - /** - * Set to true, if the duty cycle is enabled, otherwise false. - */ - bool dc_enabled; -} channel_selection_params_t; - -/*! - * The parameter structure for the function RegionContinuousWave. - */ -typedef struct continuous_wave_mode_params_s { - /*! - * The current channel index. - */ - uint8_t channel; - /*! - * The datarate. Used to limit the TX power. - */ - int8_t datarate; - /*! - * The TX power to set up. - */ - int8_t tx_power; - /*! - * The max EIRP, if applicable. - */ - float max_eirp; - /*! - * The antenna gain, if applicable. - */ - float antenna_gain; - /*! - * Specifies the time the radio will stay in CW mode. - */ - uint16_t timeout; -} cw_mode_params_t; - -/*! - * Template for a table - */ -typedef struct { - void *table; - uint8_t size; -} loraphy_table_t; - -/*! - * Contains information regarding channel configuration of - * a given PHY - */ -typedef struct { - uint8_t channel_list_size; - uint8_t mask_size; - uint16_t *mask; - uint16_t *default_mask; - channel_params_t *channel_list; -} loraphy_channels_t; - -/*! - * Global configuration parameters of a given PHY - */ -typedef struct { - bool duty_cycle_enabled; - bool accept_tx_param_setup_req; - bool fsk_supported; - bool cflist_supported; - bool custom_channelplans_supported; - bool dl_channel_req_supported; - - uint8_t default_channel_cnt; - uint8_t cflist_channel_cnt; - uint8_t max_channel_cnt; - uint8_t min_tx_power; - uint8_t max_tx_power; - uint8_t default_tx_power; - uint8_t adr_ack_limit; - uint8_t adr_ack_delay; - - uint8_t min_tx_datarate; - uint8_t max_tx_datarate; - uint8_t min_rx_datarate; - uint8_t max_rx_datarate; - uint8_t default_datarate; - uint8_t default_max_datarate; - uint8_t min_rx1_dr_offset; - uint8_t max_rx1_dr_offset; - uint8_t default_rx1_dr_offset; - uint8_t dwell_limit_datarate; - - uint16_t max_rx_window; - uint16_t recv_delay1; - uint16_t recv_delay2; - uint16_t join_accept_delay1; - uint16_t join_accept_delay2; - uint16_t join_channel_mask; - uint16_t max_fcnt_gap; - uint16_t ack_timeout; - uint16_t ack_timeout_rnd; - - float default_max_eirp; - float default_antenna_gain; - - uint8_t rx_window2_datarate; - uint32_t rx_window2_frequency; - - loraphy_table_t bands; - loraphy_table_t bandwidths; - loraphy_table_t datarates; - loraphy_table_t payloads; - loraphy_table_t payloads_with_repeater; - - loraphy_channels_t channels; - - - unsigned ul_dwell_time_setting : 1; - unsigned dl_dwell_time_setting : 1; - -} loraphy_params_t; - - -#endif /* MBED_OS_LORA_PHY_DATASTRUCTURES_ */ diff --git a/features/lorawan/lorastack/phy/loraphy_target.h b/features/lorawan/lorastack/phy/loraphy_target.h deleted file mode 100644 index cef9be9..0000000 --- a/features/lorawan/lorastack/phy/loraphy_target.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2017, 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. - */ - -#ifndef LORAPHY_TARGET -#define LORAPHY_TARGET - -#ifdef MBED_CONF_LORA_PHY - -#define LORA_REGION_EU868 0x10 -#define LORA_REGION_AS923 0x11 -#define LORA_REGION_AU915 0x12 -#define LORA_REGION_CN470 0x13 -#define LORA_REGION_CN779 0x14 -#define LORA_REGION_EU433 0x15 -#define LORA_REGION_IN865 0x16 -#define LORA_REGION_KR920 0x17 -#define LORA_REGION_US915 0x18 - -//DO NOT USE integer values in mbed_app.json! -//These are defined for backward compatibility and -//Will be DEPRECATED in the future -#define LORA_REGION_0 0x10 -#define LORA_REGION_1 0x11 -#define LORA_REGION_2 0x12 -#define LORA_REGION_3 0x13 -#define LORA_REGION_4 0x14 -#define LORA_REGION_5 0x15 -#define LORA_REGION_6 0x16 -#define LORA_REGION_7 0x17 -#define LORA_REGION_8 0x18 - -//Since 0 would be equal to any undefined value we need to handle this in a other way -#define mbed_lora_concat_(x) LORA_REGION_##x -#define mbed_lora_concat(x) mbed_lora_concat_(x) -#define LORA_REGION mbed_lora_concat(MBED_CONF_LORA_PHY) - -#if LORA_REGION == LORA_REGION_EU868 -#include "lorawan/lorastack/phy/LoRaPHYEU868.h" -#define LoRaPHY_region LoRaPHYEU868 -#elif LORA_REGION == LORA_REGION_AS923 -#include "lorawan/lorastack/phy/LoRaPHYAS923.h" -#define LoRaPHY_region LoRaPHYAS923 -#elif LORA_REGION == LORA_REGION_AU915 -#include "lorawan/lorastack/phy/LoRaPHYAU915.h" -#define LoRaPHY_region LoRaPHYAU915 -#elif LORA_REGION == LORA_REGION_CN470 -#include "lorawan/lorastack/phy/LoRaPHYCN470.h" -#define LoRaPHY_region LoRaPHYCN470 -#elif LORA_REGION == LORA_REGION_CN779 -#include "lorawan/lorastack/phy/LoRaPHYCN779.h" -#define LoRaPHY_region LoRaPHYCN779 -#elif LORA_REGION == LORA_REGION_EU433 -#include "lorawan/lorastack/phy/LoRaPHYEU433.h" -#define LoRaPHY_region LoRaPHYEU433 -#elif LORA_REGION == LORA_REGION_IN865 -#include "lorawan/lorastack/phy/LoRaPHYIN865.h" -#define LoRaPHY_region LoRaPHYIN865 -#elif LORA_REGION == LORA_REGION_KR920 -#include "lorawan/lorastack/phy/LoRaPHYKR920.h" -#define LoRaPHY_region LoRaPHYKR920 -#elif LORA_REGION == LORA_REGION_US915 -#include "lorawan/lorastack/phy/LoRaPHYUS915.h" -#define LoRaPHY_region LoRaPHYUS915 -#else -#error "Invalid region configuration, update mbed_app.json with correct MBED_CONF_LORA_PHY value" -#endif //MBED_CONF_LORA_PHY == VALUE -#else -#error "Must set LoRa PHY layer parameters." -#endif //MBED_CONF_LORA_PHY - -#endif // LORAPHY_TARGET - diff --git a/features/lorawan/lorawan_types.h b/features/lorawan/lorawan_types.h deleted file mode 100644 index 324a5bc..0000000 --- a/features/lorawan/lorawan_types.h +++ /dev/null @@ -1,679 +0,0 @@ -/** - * @file lorawan_types.h - * - * @brief Contains data structures required by LoRaWANBase class. - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef MBED_LORAWAN_TYPES_H_ -#define MBED_LORAWAN_TYPES_H_ - -#include "platform/Callback.h" - -/** - * A mask for the network ID. - */ -#define LORAWAN_NETWORK_ID_MASK (uint32_t) 0xFE000000 - -/** - * Option Flags for send(), receive() APIs - * - * Special Notes for UPLINK: - * i) All of the flags are mutually exclusive. - * ii) MSG_MULTICAST_FLAG cannot be used. - */ -#define MSG_UNCONFIRMED_FLAG 0x01 -#define MSG_CONFIRMED_FLAG 0x02 -#define MSG_MULTICAST_FLAG 0x04 -#define MSG_PROPRIETARY_FLAG 0x08 - -/** - * LoRaWAN device classes definition. - * - * LoRaWAN Specification V1.0.2, chapter 2.1. - */ -typedef enum { - /** - * LoRaWAN device class A. - * - * LoRaWAN Specification V1.0.2, chapter 3. - */ - CLASS_A, - /** - * LoRaWAN device class B. - * - * LoRaWAN Specification V1.0.2, chapter 8. - */ - CLASS_B, - /** - * LoRaWAN device class C. - * - * LoRaWAN Specification V1.0.2, chapter 17. - */ - CLASS_C, -} device_class_t; - -/** - * lorawan_status_t contains status codes in - * response to stack operations - */ -typedef enum lorawan_status { - LORAWAN_STATUS_OK = 0, /**< Service started successfully */ - LORAWAN_STATUS_BUSY = -1000, /**< Service not started - LoRaMAC is busy */ - LORAWAN_STATUS_WOULD_BLOCK = -1001, /**< LoRaMAC cannot send at the moment or have nothing to read */ - LORAWAN_STATUS_SERVICE_UNKNOWN = -1002, /**< Service unknown */ - LORAWAN_STATUS_PARAMETER_INVALID = -1003, /**< Service not started - invalid parameter */ - LORAWAN_STATUS_FREQUENCY_INVALID = -1004, /**< Service not started - invalid frequency */ - LORAWAN_STATUS_DATARATE_INVALID = -1005, /**< Service not started - invalid datarate */ - LORAWAN_STATUS_FREQ_AND_DR_INVALID = -1006, /**< Service not started - invalid frequency and datarate */ - LORAWAN_STATUS_NO_NETWORK_JOINED = -1009, /**< Service not started - the device is not in a LoRaWAN */ - LORAWAN_STATUS_LENGTH_ERROR = -1010, /**< Service not started - payload lenght error */ - LORAWAN_STATUS_DEVICE_OFF = -1011, /**< Service not started - the device is switched off */ - LORAWAN_STATUS_NOT_INITIALIZED = -1012, /**< Service not started - stack not initialized */ - LORAWAN_STATUS_UNSUPPORTED = -1013, /**< Service not supported */ - LORAWAN_STATUS_CRYPTO_FAIL = -1014, /**< Service not started - crypto failure */ - LORAWAN_STATUS_PORT_INVALID = -1015, /**< Invalid port */ - LORAWAN_STATUS_CONNECT_IN_PROGRESS = -1016, /**< Services started - Connection in progress */ - LORAWAN_STATUS_NO_ACTIVE_SESSIONS = -1017, /**< Services not started - No active session */ - LORAWAN_STATUS_IDLE = -1018, /**< Services started - Idle at the moment */ - LORAWAN_STATUS_NO_OP = -1019, /**< Cannot perform requested operation */ - LORAWAN_STATUS_DUTYCYCLE_RESTRICTED = -1020, /**< Transmission will continue after duty cycle backoff*/ - LORAWAN_STATUS_NO_CHANNEL_FOUND = -1021, /**< None of the channels is enabled at the moment*/ - LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND = -1022, /**< None of the enabled channels is ready for another TX (duty cycle limited)*/ - LORAWAN_STATUS_METADATA_NOT_AVAILABLE = -1023, /**< Meta-data after an RX or TX is stale*/ - LORAWAN_STATUS_ALREADY_CONNECTED = -1024 /**< The device has already joined a network*/ -} lorawan_status_t; - -/** The lorawan_connect_otaa structure. - * - * A structure representing the LoRaWAN Over The Air Activation - * parameters. - */ -typedef struct { - /** End-device identifier - * - * LoRaWAN Specification V1.0.2, chapter 6.2.1 - */ - uint8_t *dev_eui; - /** Application identifier - * - * LoRaWAN Specification V1.0.2, chapter 6.1.2 - */ - uint8_t *app_eui; - /** AES-128 application key - * - * LoRaWAN Specification V1.0.2, chapter 6.2.2 - */ - uint8_t *app_key; - /** Join request trials - * - * Number of trials for the join request. - */ - uint8_t nb_trials; -} lorawan_connect_otaa_t; - -/** The lorawan_connect_abp structure. - * - * A structure representing the LoRaWAN Activation By Personalization - * parameters. - */ -typedef struct { - /** Network identifier - * - * LoRaWAN Specification V1.0.2, chapter 6.1.1 - */ - uint32_t nwk_id; - /** End-device address - * - * LoRaWAN Specification V1.0.2, chapter 6.1.1 - */ - uint32_t dev_addr; - /** Network session key - * - * LoRaWAN Specification V1.0.2, chapter 6.1.3 - */ - uint8_t *nwk_skey; - /** Application session key - * - * LoRaWAN Specification V1.0.2, chapter 6.1.4 - */ - uint8_t *app_skey; -} lorawan_connect_abp_t; - -/** lorawan_connect_t structure - * - * A structure representing the parameters for different connections. - */ -typedef struct lorawan_connect { - /** - * Select the connection type, either LORAWAN_CONNECTION_OTAA - * or LORAWAN_CONNECTION_ABP. - */ - uint8_t connect_type; - - union { - /** - * Join the network using OTA - */ - lorawan_connect_otaa_t otaa; - /** - * Authentication by personalization - */ - lorawan_connect_abp_t abp; - } connection_u; - -} lorawan_connect_t; - -/** - * Events needed to announce stack operation results. - * - * CONNECTED - When the connection is complete - * DISCONNECTED - When the protocol is shut down in response to disconnect() - * TX_DONE - When a packet is sent - * TX_TIMEOUT, - When stack was unable to send packet in TX window - * TX_ERROR, - A general TX error - * CRYPTO_ERROR, - A crypto error indicating wrong keys - * TX_SCHEDULING_ERROR, - When stack is unable to schedule packet - * RX_DONE, - When there is something to receive - * RX_TIMEOUT, - Not yet mapped - * RX_ERROR - A general RX error - * JOIN_FAILURE - When all Joining retries are exhausted - * UPLINK_REQUIRED - Stack indicates application that some uplink needed - * AUTOMATIC_UPLINK_ERROR - Stack tried automatically send uplink but some error occurred. - * Application should initiate uplink as soon as possible. - * - */ -typedef enum lora_events { - CONNECTED = 0, - DISCONNECTED, - TX_DONE, - TX_TIMEOUT, - TX_ERROR, - CRYPTO_ERROR, - TX_CRYPTO_ERROR = CRYPTO_ERROR, //keeping this for backward compatibility - TX_SCHEDULING_ERROR, - RX_DONE, - RX_TIMEOUT, - RX_ERROR, - JOIN_FAILURE, - UPLINK_REQUIRED, - AUTOMATIC_UPLINK_ERROR, -} lorawan_event_t; - -/** - * Stack level callback functions - * - * 'lorawan_app_callbacks_t' is a structure that holds pointers to the application - * provided methods which are needed to be called in response to certain - * requests. The structure is default constructed to set all pointers to NULL. - * So if the user does not provide the pointer, a response will not be posted. - * However, the 'lorawan_events' callback is mandatory to be provided as it - * contains essential events. - * - * A link check request could be sent whenever the device tries to send a - * message and if the network server responds with a link check response, - * the stack notifies the application be calling the appropriate method set using - * 'link_check_resp' callback. The result is thus transported to the application - * via callback function provided. - * - * 'battery_level' callback goes in the down direction, i.e., it informs - * the stack about the battery level by calling a function provided - * by the upper layers. - */ -typedef struct { - /** - * Mandatory. Event Callback must be provided - */ - mbed::Callback events; - - /** - * This callback is optional - * - * The first parameter to the callback function is the demodulation margin, and the second - * parameter is the number of gateways that successfully received the last request. - */ - mbed::Callback link_check_resp; - - /** - * This callback is optional. If the callback is not set, the stack returns 255 to gateway. - * - * Battery level return value must follow the specification - * for DevStatusAns MAC command: - * - * 0 The end-device is connected to an external power source - * 1 - 254 The battery level, 1 being at minimum and 254 being at maximum - * 255 The end-device was not able to measure the battery level. - */ - mbed::Callback battery_level; -} lorawan_app_callbacks_t; - -/** - * DO NOT MODIFY, WILL BREAK THE API! - * - * Structure containing a given data rate range. - */ -typedef union { - /** - * Byte-access to the bits. - */ - uint8_t value; - /** - * The structure to store the minimum and the maximum datarate. - */ - struct fields_s { - /** - * The minimum data rate. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. - * Please refer to \ref DR_0 to \ref DR_15 for details. - */ - uint8_t min : 4; - /** - * The maximum data rate. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. - * Please refer to \ref DR_0 to \ref DR_15 for details. - */ - uint8_t max : 4; - } fields; -} dr_range_t; - -/** - * DO NOT MODIFY, WILL BREAK THE API! - * - * LoRaMAC channel definition. - */ -typedef struct { - /** - * The frequency in Hz. - */ - uint32_t frequency; - /** - * The alternative frequency for RX window 1. - */ - uint32_t rx1_frequency; - /** - * The data rate definition. - */ - dr_range_t dr_range; - /** - * The band index. - */ - uint8_t band; -} channel_params_t; - -/** - * DO NOT MODIFY, WILL BREAK THE API! - * - * Structure to hold parameters for a LoRa channel. - */ -typedef struct lora_channels_s { - uint8_t id; - channel_params_t ch_param; -} loramac_channel_t; - -/** - * DO NOT MODIFY, WILL BREAK THE API! - * - * This data structures contains LoRaWAN channel plan, i.e., a pointer to a - * list of channels and the total number of channels included in the plan. - */ -typedef struct lora_channelplan { - uint8_t nb_channels; // number of channels - loramac_channel_t *channels; -} lorawan_channelplan_t; - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF12 - BW125 - * AU915 | SF10 - BW125 - * CN470 | SF12 - BW125 - * CN779 | SF12 - BW125 - * EU433 | SF12 - BW125 - * EU868 | SF12 - BW125 - * IN865 | SF12 - BW125 - * KR920 | SF12 - BW125 - * US915 | SF10 - BW125 - * US915_HYBRID | SF10 - BW125 - */ -#define DR_0 0 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF11 - BW125 - * AU915 | SF9 - BW125 - * CN470 | SF11 - BW125 - * CN779 | SF11 - BW125 - * EU433 | SF11 - BW125 - * EU868 | SF11 - BW125 - * IN865 | SF11 - BW125 - * KR920 | SF11 - BW125 - * US915 | SF9 - BW125 - * US915_HYBRID | SF9 - BW125 - */ -#define DR_1 1 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF10 - BW125 - * AU915 | SF8 - BW125 - * CN470 | SF10 - BW125 - * CN779 | SF10 - BW125 - * EU433 | SF10 - BW125 - * EU868 | SF10 - BW125 - * IN865 | SF10 - BW125 - * KR920 | SF10 - BW125 - * US915 | SF8 - BW125 - * US915_HYBRID | SF8 - BW125 - */ -#define DR_2 2 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF9 - BW125 - * AU915 | SF7 - BW125 - * CN470 | SF9 - BW125 - * CN779 | SF9 - BW125 - * EU433 | SF9 - BW125 - * EU868 | SF9 - BW125 - * IN865 | SF9 - BW125 - * KR920 | SF9 - BW125 - * US915 | SF7 - BW125 - * US915_HYBRID | SF7 - BW125 - */ -#define DR_3 3 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF8 - BW125 - * AU915 | SF8 - BW500 - * CN470 | SF8 - BW125 - * CN779 | SF8 - BW125 - * EU433 | SF8 - BW125 - * EU868 | SF8 - BW125 - * IN865 | SF8 - BW125 - * KR920 | SF8 - BW125 - * US915 | SF8 - BW500 - * US915_HYBRID | SF8 - BW500 - */ -#define DR_4 4 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF7 - BW125 - * AU915 | RFU - * CN470 | SF7 - BW125 - * CN779 | SF7 - BW125 - * EU433 | SF7 - BW125 - * EU868 | SF7 - BW125 - * IN865 | SF7 - BW125 - * KR920 | SF7 - BW125 - * US915 | RFU - * US915_HYBRID | RFU - */ -#define DR_5 5 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | SF7 - BW250 - * AU915 | RFU - * CN470 | SF12 - BW125 - * CN779 | SF7 - BW250 - * EU433 | SF7 - BW250 - * EU868 | SF7 - BW250 - * IN865 | SF7 - BW250 - * KR920 | RFU - * US915 | RFU - * US915_HYBRID | RFU - */ -#define DR_6 6 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | FSK - * AU915 | RFU - * CN470 | SF12 - BW125 - * CN779 | FSK - * EU433 | FSK - * EU868 | FSK - * IN865 | FSK - * KR920 | RFU - * US915 | RFU - * US915_HYBRID | RFU - */ -#define DR_7 7 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF12 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF12 - BW500 - * US915_HYBRID | SF12 - BW500 - */ -#define DR_8 8 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF11 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF11 - BW500 - * US915_HYBRID | SF11 - BW500 - */ -#define DR_9 9 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF10 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF10 - BW500 - * US915_HYBRID | SF10 - BW500 - */ -#define DR_10 10 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF9 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF9 - BW500 - * US915_HYBRID | SF9 - BW500 - */ -#define DR_11 11 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF8 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF8 - BW500 - * US915_HYBRID | SF8 - BW500 - */ -#define DR_12 12 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | SF7 - BW500 - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | SF7 - BW500 - * US915_HYBRID | SF7 - BW500 - */ -#define DR_13 13 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | RFU - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | RFU - * US915_HYBRID | RFU - */ -#define DR_14 14 - -/*! - * Region | SF - * ------------ | :-----: - * AS923 | RFU - * AU915 | RFU - * CN470 | RFU - * CN779 | RFU - * EU433 | RFU - * EU868 | RFU - * IN865 | RFU - * KR920 | RFU - * US915 | RFU - * US915_HYBRID | RFU - */ -#define DR_15 15 - -/** - * Enumeration for LoRaWAN connection type. - */ -typedef enum lorawan_connect_type { - LORAWAN_CONNECTION_OTAA = 0, /**< Over The Air Activation */ - LORAWAN_CONNECTION_ABP /**< Activation By Personalization */ -} lorawan_connect_type_t; - - -/** - * Meta-data collection for a transmission - */ -typedef struct { - /** - * The transmission time on air of the frame. - */ - uint32_t tx_toa; - /** - * The uplink channel used for transmission. - */ - uint32_t channel; - /** - * The transmission power. - */ - int8_t tx_power; - /** - * The uplink datarate. - */ - uint8_t data_rate; - /** - * Provides the number of retransmissions. - */ - uint8_t nb_retries; - /** - * A boolean to mark if the meta data is stale - */ - bool stale; -} lorawan_tx_metadata; - -/** - * Meta-data collection for the received packet - */ -typedef struct { - /** - * The RSSI for the received packet. - */ - int16_t rssi; - /** - * Data rate of reception - */ - uint8_t rx_datarate; - /** - * The SNR for the received packet. - */ - int8_t snr; - /** - * A boolean to mark if the meta data is stale - */ - bool stale; - /** - * Frequency for the downlink channel - */ - uint32_t channel; - /** - * Time spent on air by the RX frame - */ - uint32_t rx_toa; -} lorawan_rx_metadata; - -#endif /* MBED_LORAWAN_TYPES_H_ */ diff --git a/features/lorawan/mbed_lib.json b/features/lorawan/mbed_lib.json deleted file mode 100644 index 30e130b..0000000 --- a/features/lorawan/mbed_lib.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "name": "lora", - "config": { - "phy": { - "help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915", - "value": "EU868" - }, - "over-the-air-activation": { - "help": "When set to 1 the application uses the Over-the-Air activation procedure, default: true", - "value": true - }, - "nb-trials": { - "help": "Indicates how many times join can be tried, default: 12", - "value": 12 - }, - "device-eui": { - "help": "Mote device IEEE EUI", - "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" - }, - "application-eui": { - "help": "Application IEEE EUI", - "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" - }, - "application-key": { - "help": "AES encryption/decryption cipher application key", - "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" - }, - "device-address": { - "help": "Device address on the network", - "value": "0x00000000" - }, - "nwkskey": { - "help": "AES encryption/decryption cipher network session key", - "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" - }, - "appskey": { - "help": "AES encryption/decryption cipher application session key", - "value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" - }, - "app-port": { - "help": "LoRaWAN application port, default: 15", - "value": 15 - }, - "tx-max-size": { - "help": "User application data buffer maximum size, default: 64, MAX: 255", - "value": 64 - }, - "adr-on": { - "help": "LoRaWAN Adaptive Data Rate, default: 1", - "value": 1 - }, - "public-network": { - "help": "LoRaWAN will connect to a public network or private network, true = public network", - "value": true - }, - "duty-cycle-on": { - "help": "Enables/disables duty cycling. NOTE: Disable only for testing. Mandatory in many regions.", - "value": true - }, - "duty-cycle-on-join": { - "help": "Enables/disables duty cycling for JOIN requests (disabling requires duty-cycle-on to be disabled). NOTE: Disable only for testing!", - "value": true - }, - "lbt-on": { - "help": "Enables/disables LBT. NOTE: [This feature is not yet integrated].", - "value": false - }, - "automatic-uplink-message": { - "help": "Stack will automatically send an uplink message when lora server requires immediate response", - "value": true - }, - "max-sys-rx-error": { - "help": "Max. timing error fudge. The receiver will turn on in [-RxError : + RxError]", - "value": 5 - }, - "wakeup-time": { - "help": "Time in (ms) the platform takes to wakeup from sleep/deep sleep state. This number is platform dependent", - "value": 5 - }, - "downlink-preamble-length": { - "help": "Number of whole preamble symbols needed to have a firm lock on the signal.", - "value": 5 - }, - "uplink-preamble-length": { - "help": "Number of preamble symbols to transmit. Default: 8", - "value": 8 - }, - "fsb-mask": { - "help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details", - "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}" - }, - "fsb-mask-china": { - "help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details", - "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}" - } - } -} diff --git a/features/lorawan/system/LoRaWANTimer.cpp b/features/lorawan/system/LoRaWANTimer.cpp deleted file mode 100644 index d17b96b..0000000 --- a/features/lorawan/system/LoRaWANTimer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - -Description: Timer objects and scheduling management - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis and Gregory Cristian - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#include "LoRaWANTimer.h" - -using namespace std::chrono; - -LoRaWANTimeHandler::LoRaWANTimeHandler() - : _queue(NULL) -{ -} - -LoRaWANTimeHandler::~LoRaWANTimeHandler() -{ -} - -void LoRaWANTimeHandler::activate_timer_subsystem(events::EventQueue *queue) -{ - _queue = queue; -} - -lorawan_time_t LoRaWANTimeHandler::get_current_time(void) -{ - const uint32_t current_time = _queue->tick(); - return (lorawan_time_t)current_time; -} - -lorawan_time_t LoRaWANTimeHandler::get_elapsed_time(lorawan_time_t saved_time) -{ - return get_current_time() - saved_time; -} - -void LoRaWANTimeHandler::init(timer_event_t &obj, mbed::Callback callback) -{ - obj.callback = callback; - obj.timer_id = 0; -} - -void LoRaWANTimeHandler::start(timer_event_t &obj, const uint32_t timeout) -{ - obj.timer_id = _queue->call_in(milliseconds(timeout), obj.callback); - MBED_ASSERT(obj.timer_id != 0); -} - -void LoRaWANTimeHandler::stop(timer_event_t &obj) -{ - _queue->cancel(obj.timer_id); - obj.timer_id = 0; -} diff --git a/features/lorawan/system/LoRaWANTimer.h b/features/lorawan/system/LoRaWANTimer.h deleted file mode 100644 index e66d268..0000000 --- a/features/lorawan/system/LoRaWANTimer.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - -Description: Timer objects and scheduling management - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis and Gregory Cristian - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ - -#ifndef MBED_LORAWAN_SYS_TIMER_H__ -#define MBED_LORAWAN_SYS_TIMER_H__ - -#include -#include "events/EventQueue.h" - -#include "lorawan_data_structures.h" - -class LoRaWANTimeHandler { -public: - LoRaWANTimeHandler(); - ~LoRaWANTimeHandler(); - - /** Activates the timer subsystem. - * - * Embeds EventQueue object to timer subsystem which is subsequently - * used to extract timer information. - * - * @param [in] queue Handle to EventQueue object - */ - void activate_timer_subsystem(events::EventQueue *queue); - - /** Read the current time. - * - * @return time The current time. - */ - lorawan_time_t get_current_time(void); - - /** Return the time elapsed since a fixed moment in time. - * - * @param [in] saved_time The fixed moment in time. - * @return time The elapsed time. - */ - lorawan_time_t get_elapsed_time(lorawan_time_t saved_time); - - /** Initializes the timer object. - * - * @remark The TimerSetValue function must be called before starting the timer. - * This function initializes the time-stamp and reloads the value at 0. - * - * @param [in] obj The structure containing the timer object parameters. - * @param [in] callback The function callback called at the end of the timeout. - */ - void init(timer_event_t &obj, mbed::Callback callback); - - /** Starts and adds the timer object to the list of timer events. - * - * @param [in] obj The structure containing the timer object parameters. - * @param [in] timeout The new timeout value. - */ - void start(timer_event_t &obj, const uint32_t timeout); - - /** Stops and removes the timer object from the list of timer events. - * - * @param [in] obj The structure containing the timer object parameters. - */ - void stop(timer_event_t &obj); - -private: - events::EventQueue *_queue; -}; - -#endif // MBED_LORAWAN_SYS_TIMER_H__ diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h deleted file mode 100644 index 7ce8cb3..0000000 --- a/features/lorawan/system/lorawan_data_structures.h +++ /dev/null @@ -1,1313 +0,0 @@ -/** - * @file lorawan_data_structures.h - * - * @brief Contains common data structures used by Mbed-OS - * LoRaWAN mplementation. - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * Description: LoRa PHY layer - * - * License: Revised BSD License, see LICENSE.TXT file include in the project - * - * Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - * - * Copyright (c) 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ -#define LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ - -#include -#include "lorawan_types.h" - -/*! - * \brief Timer time variable definition - */ -#ifndef lorawan_time_t -typedef uint32_t lorawan_time_t; -#endif - -/*! - * Sets the length of the LoRaMAC footer field. - * Mainly indicates the MIC field length. - */ -#define LORAMAC_MFR_LEN 4 - -/*! - * The FRMPayload overhead to be used when setting the `Radio.SetMaxPayloadLength` - * in the `RxWindowSetup` function. - * The maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD - */ -#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) - -/** - * LoRaMac maximum number of channels - */ -#define LORA_MAX_NB_CHANNELS 16 - -/** - * Maximum PHY layer payload size for reception. - */ -#define LORAMAC_PHY_MAXPAYLOAD 255 - -#define LORAWAN_DEFAULT_QOS 1 - -/** - * - * Default user application maximum data size for transmission - */ -// reject if user tries to set more than MTU -#if MBED_CONF_LORA_TX_MAX_SIZE > 255 -#warning "Cannot set TX Max size more than MTU=255" -#define MBED_CONF_LORA_TX_MAX_SIZE 255 -#endif - -/*! - * LoRaMAC band parameters definition. - */ -typedef struct { - /*! - * The duty cycle. - */ - uint16_t duty_cycle; - /*! - * The maximum TX power. - */ - int8_t max_tx_pwr; - /*! - * The timestamp of the last Join Request TX frame. - */ - lorawan_time_t last_join_tx_time; - /*! - * The timestamp of the last TX frame. - */ - lorawan_time_t last_tx_time; - /*! - * The device off time. - */ - lorawan_time_t off_time; - /*! - * Lower band boundry - */ - uint32_t lower_band_freq; - /*! - * Higher band boundry - */ - uint32_t higher_band_freq; -} band_t; - -/*! - * LoRaMAC receive window 2 channel parameters. - */ -typedef struct { - /*! - * The frequency in Hz. - */ - uint32_t frequency; - /*! - * The data rate. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. Please refer to \ref DR_0 to \ref DR_15 for details. - */ - uint8_t datarate; -} rx2_channel_params; - -/*! - * LoRaMAC receive window enumeration - */ -typedef enum { - /*! - * LoRaMAC receive window 1 - */ - RX_SLOT_WIN_1, - /*! - * LoRaMAC receive window 2 - */ - RX_SLOT_WIN_2, - /*! - * LoRaMAC receive window 2 for class c - continuous listening - */ - RX_SLOT_WIN_CLASS_C, - /*! - * LoRaMAC class b ping slot window - */ - RX_SLOT_WIN_PING_SLOT -} rx_slot_t; - -/*! - * The global MAC layer parameters. - */ -typedef struct { - /*! - * The TX power in channels. - */ - int8_t channel_tx_power; - /*! - * The data rate in channels. - */ - int8_t channel_data_rate; - /*! - * LoRaMac maximum time a reception window stays open. - */ - uint32_t max_rx_win_time; - /*! - * Receive delay 1. - */ - uint32_t recv_delay1; - /*! - * Receive delay 2. - */ - uint32_t recv_delay2; - /*! - * Join accept delay 1. - */ - uint32_t join_accept_delay1; - /*! - * Join accept delay 1. - */ - uint32_t join_accept_delay2; - /*! - * The number of uplink messages repetitions for QOS set by network server - * in LinkADRReq mac command (unconfirmed messages only). - */ - uint8_t nb_trans; - /*! - * The datarate offset between uplink and downlink on first window. - */ - uint8_t rx1_dr_offset; - /*! - * LoRaMAC 2nd reception window settings. - */ - rx2_channel_params rx2_channel; - /*! - * The uplink dwell time configuration. 0: No limit, 1: 400ms - */ - uint8_t uplink_dwell_time; - /*! - * The downlink dwell time configuration. 0: No limit, 1: 400ms - */ - uint8_t downlink_dwell_time; - /*! - * The maximum possible EIRP. - */ - float max_eirp; - /*! - * The antenna gain of the node. - */ - float antenna_gain; - - /*! - * Maximum duty cycle - * \remark Possibility to shutdown the device. - */ - uint8_t max_duty_cycle; - /*! - * Aggregated duty cycle management - */ - uint16_t aggregated_duty_cycle; - - /*! - * LoRaMac ADR control status - */ - bool adr_on; -} lora_mac_system_params_t; - -/*! - * LoRaMAC multicast channel parameter. - */ -typedef struct multicast_params_s { - /*! - * Address. - */ - uint32_t address; - /*! - * Network session key. - */ - uint8_t nwk_skey[16]; - /*! - * Application session key. - */ - uint8_t app_skey[16]; - /*! - * Downlink counter. - */ - uint32_t dl_frame_counter; - /*! - * A reference pointer to the next multicast channel parameters in the list. - */ - struct multicast_params_s *next; -} multicast_params_t; - -/*! - * LoRaMAC frame types. - * - * LoRaWAN Specification V1.0.2, chapter 4.2.1, table 1. - */ -typedef enum { - /*! - * LoRaMAC join request frame. - */ - FRAME_TYPE_JOIN_REQ = 0x00, - /*! - * LoRaMAC join accept frame. - */ - FRAME_TYPE_JOIN_ACCEPT = 0x01, - /*! - * LoRaMAC unconfirmed uplink frame. - */ - FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02, - /*! - * LoRaMAC unconfirmed downlink frame. - */ - FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03, - /*! - * LoRaMAC confirmed uplink frame. - */ - FRAME_TYPE_DATA_CONFIRMED_UP = 0x04, - /*! - * LoRaMAC confirmed downlink frame. - */ - FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05, - /*! - * LoRaMAC RFU frame. - */ - FRAME_TYPE_RFU = 0x06, - /*! - * LoRaMAC proprietary frame. - */ - FRAME_TYPE_PROPRIETARY = 0x07, -} mac_frame_type_t; - -/*! - * LoRaMAC mote MAC commands. - * - * LoRaWAN Specification V1.0.2, chapter 5, table 4. - */ -typedef enum { - /*! - * LinkCheckReq - */ - MOTE_MAC_LINK_CHECK_REQ = 0x02, - /*! - * LinkADRAns - */ - MOTE_MAC_LINK_ADR_ANS = 0x03, - /*! - * DutyCycleAns - */ - MOTE_MAC_DUTY_CYCLE_ANS = 0x04, - /*! - * RXParamSetupAns - */ - MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05, - /*! - * DevStatusAns - */ - MOTE_MAC_DEV_STATUS_ANS = 0x06, - /*! - * NewChannelAns - */ - MOTE_MAC_NEW_CHANNEL_ANS = 0x07, - /*! - * RXTimingSetupAns - */ - MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08, - /*! - * TXParamSetupAns - */ - MOTE_MAC_TX_PARAM_SETUP_ANS = 0x09, - /*! - * DlChannelAns - */ - MOTE_MAC_DL_CHANNEL_ANS = 0x0A -} mote_mac_cmds_t; - -/*! - * LoRaMAC server MAC commands. - * - * LoRaWAN Specification V1.0.2 chapter 5, table 4. - */ -typedef enum { - /*! - * LinkCheckAns - */ - SRV_MAC_LINK_CHECK_ANS = 0x02, - /*! - * LinkADRReq - */ - SRV_MAC_LINK_ADR_REQ = 0x03, - /*! - * DutyCycleReq - */ - SRV_MAC_DUTY_CYCLE_REQ = 0x04, - /*! - * RXParamSetupReq - */ - SRV_MAC_RX_PARAM_SETUP_REQ = 0x05, - /*! - * DevStatusReq - */ - SRV_MAC_DEV_STATUS_REQ = 0x06, - /*! - * NewChannelReq - */ - SRV_MAC_NEW_CHANNEL_REQ = 0x07, - /*! - * RXTimingSetupReq - */ - SRV_MAC_RX_TIMING_SETUP_REQ = 0x08, - /*! - * NewChannelReq - */ - SRV_MAC_TX_PARAM_SETUP_REQ = 0x09, - /*! - * DlChannelReq - */ - SRV_MAC_DL_CHANNEL_REQ = 0x0A, -} server_mac_cmds_t; - -/*! - * LoRaMAC battery level indicator. - */ -typedef enum { - /*! - * An external power source. - */ - BAT_LEVEL_EXT_SRC = 0x00, - /*! - * Battery level empty. - */ - BAT_LEVEL_EMPTY = 0x01, - /*! - * Battery level full. - */ - BAT_LEVEL_FULL = 0xFE, - /*! - * Battery level - no measurement available. - */ - BAT_LEVEL_NO_MEASURE = 0xFF, -} device_battery_level_t; - -/*! - * LoRaMAC header field definition (MHDR field). - * - * LoRaWAN Specification V1.0.2, chapter 4.2. - */ -typedef union { - /*! - * Byte-access to the bits. - */ - uint8_t value; - /*! - * The structure containing single access to header bits. - */ - struct hdr_bits_s { - /*! - * Major version. - */ - uint8_t major : 2; - /*! - * RFU - */ - uint8_t RFU : 3; - /*! - * Message type - */ - uint8_t mtype : 3; - } bits; -} loramac_mhdr_t; - -/*! - * LoRaMAC frame control field definition (FCtrl). - * - * LoRaWAN Specification V1.0.2, chapter 4.3.1. - */ -typedef union { - /*! - * Byte-access to the bits. - */ - uint8_t value; - /*! - * The structure containing single access to bits. - */ - struct ctrl_bits_s { - /*! - * Frame options length. - */ - uint8_t fopts_len : 4; - /*! - * Frame pending bit. - */ - uint8_t fpending : 1; - /*! - * Message acknowledge bit. - */ - uint8_t ack : 1; - /*! - * ADR acknowledgment request bit. - */ - uint8_t adr_ack_req : 1; - /*! - * ADR control in the frame header. - */ - uint8_t adr : 1; - } bits; -} loramac_frame_ctrl_t; - -/*! - * The enumeration containing the status of the operation of a MAC service. - */ -typedef enum { - /*! - * Service performed successfully. - */ - LORAMAC_EVENT_INFO_STATUS_OK = 0, - /*! - * An error occurred during the execution of the service. - */ - LORAMAC_EVENT_INFO_STATUS_ERROR, - /*! - * A TX timeout occurred. - */ - LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, - /*! - * An RX timeout occurred on receive window 1. - */ - LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, - /*! - * An RX timeout occurred on receive window 2. - */ - LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT, - /*! - * An RX error occurred on receive window 1. - */ - LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, - /*! - * An RX error occurred on receive window 2. - */ - LORAMAC_EVENT_INFO_STATUS_RX2_ERROR, - /*! - * An error occurred in the join procedure. - */ - LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, - /*! - * A frame with an invalid downlink counter was received. The - * downlink counter of the frame was equal to the local copy - * of the downlink counter of the node. - */ - LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, - /*! - * The MAC could not retransmit a frame since the MAC decreased the datarate. The - * payload size is not applicable for the datarate. - */ - LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR, - /*! - * The node has lost MAX_FCNT_GAP or more frames. - */ - LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOST, - /*! - * An address error occurred. - */ - LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, - /*! - * Message integrity check failure. - */ - LORAMAC_EVENT_INFO_STATUS_MIC_FAIL, - /*! - * Crypto methods failure - */ - LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL, -} loramac_event_info_status_t; - -/*! - * - * \brief LoRaMAC data services - * - * \details The following table list the primitives supported by a - * specific MAC data service: - * - * Name | Request | Indication | Response | Confirm - * --------------------- | :-----: | :--------: | :------: | :-----: - * \ref MCPS_UNCONFIRMED | YES | YES | NO | YES - * \ref MCPS_CONFIRMED | YES | YES | NO | YES - * \ref MCPS_MULTICAST | NO | YES | NO | NO - * \ref MCPS_PROPRIETARY | YES | YES | NO | YES - * - */ -typedef enum { - /*! - * Unconfirmed LoRaMAC frame. - */ - MCPS_UNCONFIRMED, - /*! - * Confirmed LoRaMAC frame. - */ - MCPS_CONFIRMED, - /*! - * Multicast LoRaMAC frame. - */ - MCPS_MULTICAST, - /*! - * Proprietary frame. - */ - MCPS_PROPRIETARY, -} mcps_type_t; - -/*! - * LoRaMAC MCPS-Confirm. - */ -typedef struct { - /*! - * Holds the previously performed MCPS-Request type. i.e., the type of - * the MCPS request for which this confirmation is being generated - */ - mcps_type_t req_type; - /*! - * The status of the operation. - */ - loramac_event_info_status_t status; - /*! - * The uplink datarate. - */ - uint8_t data_rate; - /*! - * The transmission power. - */ - int8_t tx_power; - /*! - * Set if an acknowledgement was received. - */ - bool ack_received; - /*! - * Provides the number of retransmissions. - */ - uint8_t nb_retries; - /*! - * The transmission time on air of the frame. - */ - lorawan_time_t tx_toa; - /*! - * The uplink counter value related to the frame. - */ - uint32_t ul_frame_counter; - /*! - * The uplink channel related to the frame. - */ - uint32_t channel; -} loramac_mcps_confirm_t; - -/*! - * LoRaMAC MCPS-Indication primitive. - */ -typedef struct { - /*! - * True if an MCPS indication was pending - */ - bool pending; - /*! - * MCPS-Indication type. - */ - mcps_type_t type; - /*! - * The status of the operation. - */ - loramac_event_info_status_t status; - /*! - * Multicast. - */ - uint8_t multicast; - /*! - * The application port. - */ - uint8_t port; - /*! - * The downlink datarate. - */ - uint8_t rx_datarate; - /*! - * Frame pending status. - */ - uint8_t fpending_status; - /*! - * A pointer to the received data stream. - */ - const uint8_t *buffer; - /*! - * The size of the received data stream. - */ - uint16_t buffer_size; - /*! - * Indicates, if data is available. - */ - bool is_data_recvd; - /*! - * The RSSI of the received packet. - */ - int16_t rssi; - /*! - * The SNR of the received packet. - */ - int8_t snr; - /*! - * The receive window. - * - * [0: Rx window 1, 1: Rx window 2] - */ - rx_slot_t rx_slot; - /*! - * Set if an acknowledgement was received. - */ - bool is_ack_recvd; - /*! - * The downlink counter value for the received frame. - */ - uint32_t dl_frame_counter; - /*! - * The downlink channel - */ - uint32_t channel; - /*! - * The time on air of the received frame. - */ - lorawan_time_t rx_toa; -} loramac_mcps_indication_t; - -/*! - * \brief LoRaMAC management services. - * - * \details The following table list the primitives supported by a - * specific MAC management service: - * - * Name | Request | Indication | Response | Confirm - * ---------------------------- | :-----: | :--------: | :------: | :-----: - * \ref MLME_JOIN | YES | NO | NO | YES - * \ref MLME_LINK_CHECK | YES | NO | NO | YES - * \ref MLME_TXCW | YES | NO | NO | YES - * \ref MLME_SCHEDULE_UPLINK | NO | YES | NO | NO - * - */ -typedef enum { - /*! - * Initiates the Over-the-Air activation. - * - * LoRaWAN Specification V1.0.2, chapter 6.2. - */ - MLME_JOIN, - /*! - * LinkCheckReq - Connectivity validation. - * - * LoRaWAN Specification V1.0.2, chapter 5, table 4. - */ - MLME_LINK_CHECK, - /*! - * Sets TX continuous wave mode. - * - * LoRaWAN end-device certification. - */ - MLME_TXCW, - /*! - * Sets TX continuous wave mode (new LoRa-Alliance CC definition). - * - * LoRaWAN end-device certification. - */ - MLME_TXCW_1, - /*! - * Indicates that the application shall perform an uplink as - * soon as possible. - */ - MLME_SCHEDULE_UPLINK -} mlme_type_t; - -/*! - * LoRaMAC MLME-Request for the join service. - */ -typedef struct { - /*! - * A globally unique end-device identifier. - * - * LoRaWAN Specification V1.0.2, chapter 6.2.1. - */ - uint8_t *dev_eui; - /*! - * An application identifier. - * - * LoRaWAN Specification V1.0.2, chapter 6.1.2 - */ - uint8_t *app_eui; - /*! - * AES-128 application key. - * - * LoRaWAN Specification V1.0.2, chapter 6.2.2. - */ - uint8_t *app_key; - /*! - * The number of trials for the join request. - */ - uint8_t nb_trials; -} mlme_join_req_t; - -/*! - * LoRaMAC MLME-Request for TX continuous wave mode. - */ -typedef struct { - /*! - * The time while the radio is kept in continuous wave mode, in seconds. - */ - uint16_t timeout; - /*! - * The RF frequency to set (only used with the new way). - */ - uint32_t frequency; - /*! - * The RF output power to set (only used with the new way). - */ - uint8_t power; -} mlme_cw_tx_mode_t; - - -/*! - * LoRaMAC MLME-Confirm primitive. - */ -typedef struct { - /*! - * Indicates if a request is pending or not - */ - bool pending; - /*! - * The previously performed MLME-Request. i.e., the request type - * for which the confirmation is being generated - */ - mlme_type_t req_type; - /*! - * The status of the operation. - */ - loramac_event_info_status_t status; - /*! - * The transmission time on air of the frame. - */ - lorawan_time_t tx_toa; - /*! - * The demodulation margin. Contains the link margin [dB] of the last LinkCheckReq - * successfully received. - */ - uint8_t demod_margin; - /*! - * The number of gateways which received the last LinkCheckReq. - */ - uint8_t nb_gateways; - /*! - * The number of retransmissions. - */ - uint8_t nb_retries; -} loramac_mlme_confirm_t; - -/*! - * LoRaMAC MLME-Indication primitive - */ -typedef struct { - /*! - * MLME-Indication type - */ - mlme_type_t indication_type; - bool pending; -} loramac_mlme_indication_t; - -/** - * End-device states. - */ -typedef enum device_states { - DEVICE_STATE_NOT_INITIALIZED, - DEVICE_STATE_JOINING, - DEVICE_STATE_IDLE, - DEVICE_STATE_CONNECTING, - DEVICE_STATE_AWAITING_JOIN_ACCEPT, - DEVICE_STATE_RECEIVING, - DEVICE_STATE_CONNECTED, - DEVICE_STATE_SCHEDULING, - DEVICE_STATE_SENDING, - DEVICE_STATE_AWAITING_ACK, - DEVICE_STATE_STATUS_CHECK, - DEVICE_STATE_SHUTDOWN -} device_states_t; - -/** - * Stack level TX message structure - */ -typedef struct { - - /** - * TX Ongoing flag - */ - bool tx_ongoing; - - /** - * Application Port Number - */ - uint8_t port; - - /** - * Message type - */ - mcps_type_t type; - - /*! - * Frame port field. Must be set if the payload is not empty. Use the - * application-specific frame port values: [1...223]. - * - * LoRaWAN Specification V1.0.2, chapter 4.3.2. - */ - uint8_t fport; - - /*! - * Uplink datarate, if ADR is off. - */ - int8_t data_rate; - /*! - * - * For CONFIRMED Messages: - * - * The number of trials to transmit the frame, if the LoRaMAC layer did not - * receive an acknowledgment. The MAC performs a datarate adaptation - * according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in - * the following table: - * - * Transmission nb | Data Rate - * ----------------|----------- - * 1 (first) | DR - * 2 | DR - * 3 | max(DR-1,0) - * 4 | max(DR-1,0) - * 5 | max(DR-2,0) - * 6 | max(DR-2,0) - * 7 | max(DR-3,0) - * 8 | max(DR-3,0) - * - * 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. - * - * 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; - - /** Payload data - * - * Base pointer to the buffer - */ - uint8_t f_buffer[MBED_CONF_LORA_TX_MAX_SIZE]; - - /** Payload size. - * - * The size of the frame payload. - */ - uint16_t f_buffer_size; - - /** - * Pending data size - */ - uint16_t pending_size; - -} loramac_tx_message_t; - -/** lora_mac_rx_message_type_t - * - * An enum representing a structure for RX messages. - */ -typedef enum { - LORAMAC_RX_MLME_CONFIRM = 0, /**< lora_mac_mlme_confirm_t */ - LORAMAC_RX_MCPS_CONFIRM, /**< lora_mac_mcps_confirm_t */ - LORAMAC_RX_MCPS_INDICATION /**< lora_mac_mcps_indication_t */ -} rx_msg_type; - -/** lora_mac_rx_message_by_type_t union - * - * A union representing a structure for RX messages. - */ -typedef union { - loramac_mlme_confirm_t mlme_confirm; - loramac_mcps_confirm_t mcps_confirm; - loramac_mcps_indication_t mcps_indication; -} rx_message_u; - -/** loramac_rx_message_t - * - * A structure representing a structure for an RX message. - */ -typedef struct { - bool receive_ready; - rx_msg_type type; - rx_message_u msg; - uint16_t pending_size; - uint16_t prev_read_size; -} loramac_rx_message_t; - -/** LoRaWAN session - * - * A structure for keeping session details. - */ -typedef struct lorawan_session { - /** - * True if the session is active - */ - bool active; - - /*! - * Select the connection type, either LORAWAN_CONNECTION_OTAA - * or LORAWAN_CONNECTION_ABP. - */ - uint8_t connect_type; - - /** - * LoRaWAN uplink counter - */ - uint32_t uplink_counter; - /** - * LoRaWAN downlink counter - */ - uint32_t downlink_counter; -} lorawan_session_t; - -/*! - * The parameter structure for the function for regional rx configuration. - */ -typedef struct { - /*! - * Type of modulation used (LoRa or FSK) - */ - uint8_t modem_type; - /*! - * The RX channel. - */ - uint8_t channel; - /*! - * The RX datarate index. - */ - uint8_t datarate; - /*! - * The RX bandwidth. - */ - uint8_t bandwidth; - /*! - * The RX datarate offset. - */ - int8_t dr_offset; - /*! - * The RX frequency. - */ - uint32_t frequency; - /*! - * The RX window timeout - Symbols - */ - uint32_t window_timeout; - /*! - * The RX window timeout - Milliseconds - */ - uint32_t window_timeout_ms; - /*! - * The RX window offset - */ - int32_t window_offset; - /*! - * The downlink dwell time. - */ - uint8_t dl_dwell_time; - /*! - * Set to true, if a repeater is supported. - */ - bool is_repeater_supported; - /*! - * Set to true, if RX should be continuous. - */ - bool is_rx_continuous; - /*! - * Sets the RX window. - */ - rx_slot_t rx_slot; -} rx_config_params_t; - -/*! - * \brief Timer object description - */ -typedef struct { - mbed::Callback callback; - int timer_id; -} timer_event_t; - -/*! - * A composite structure containing device identifiers and security keys - */ -typedef struct { - /*! - * Device IEEE EUI - */ - uint8_t *dev_eui; - - /*! - * Application IEEE EUI - */ - uint8_t *app_eui; - - /*! - * AES encryption/decryption cipher application key - */ - uint8_t *app_key; - - /*! - * AES encryption/decryption cipher network session key - * NOTE! LoRaMac determines the length of the key based on sizeof this variable - */ - uint8_t nwk_skey[16]; - - /*! - * AES encryption/decryption cipher application session key - * NOTE! LoRaMac determines the length of the key based on sizeof this variable - */ - uint8_t app_skey[16]; - -} loramac_keys; - -/*! - * A composite structure containing all the timers used in the LoRaWAN operation - */ -typedef struct { - /*! - * Aggregated duty cycle management - */ - lorawan_time_t aggregated_last_tx_time; - lorawan_time_t aggregated_timeoff; - - /*! - * Stores the time at LoRaMac initialization. - * - * \remark Used for the BACKOFF_DC computation. - */ - lorawan_time_t mac_init_time; - - /*! - * Last transmission time on air - */ - lorawan_time_t tx_toa; - - /*! - * LoRaMac duty cycle backoff timer - */ - timer_event_t backoff_timer; - - /*! - * LoRaMac reception windows timers - */ - timer_event_t rx_window1_timer; - timer_event_t rx_window2_timer; - - /*! - * Acknowledge timeout timer. Used for packet retransmissions. - */ - timer_event_t ack_timeout_timer; - -} lorawan_timers; - -/*! - * Global MAC layer configuration parameters - */ -typedef struct { - - /*! - * Holds the type of current Receive window slot - */ - rx_slot_t rx_slot; - - /*! - * Indicates if the node is connected to a private or public network - */ - bool is_nwk_public; - - /*! - * Indicates if the node supports repeaters - */ - bool is_repeater_supported; - - /*! - * Used for test purposes. Disables the opening of the reception windows. - */ - bool is_rx_window_enabled; - - /*! - * Indicates if the MAC layer has already joined a network. - */ - bool is_nwk_joined; - - /*! - * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates - * if the nodes needs to manage the server acknowledgement. - */ - bool is_node_ack_requested; - - /*! - * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates - * if the ACK bit must be set for the next transmission - */ - bool is_srv_ack_requested; - - /*! - * Enables/Disables duty cycle management (Test only) - */ - bool is_dutycycle_on; - - /*! - * Set to true, if the last uplink was a join request - */ - bool is_last_tx_join_request; - - /*! - * Indicates if the AckTimeout timer has expired or not - */ - bool is_ack_retry_timeout_expired; - - /*! - * Current channel index - */ - uint8_t channel; - - /*! - * Current channel index - */ - uint8_t last_channel_idx; - - /*! - * Uplink messages repetitions counter - */ - uint8_t ul_nb_rep_counter; - - /*! - * TX buffer used for encrypted outgoing frames - */ - uint8_t tx_buffer[LORAMAC_PHY_MAXPAYLOAD]; - - /*! - * Length of TX buffer - */ - uint16_t tx_buffer_len; - - /*! - * Used for storing decrypted RX data. - */ - uint8_t rx_buffer[LORAMAC_PHY_MAXPAYLOAD]; - - /*! - * Length of the RX buffer - */ - uint8_t rx_buffer_len; - - /*! - * Number of trials to get a frame acknowledged - */ - uint8_t max_ack_timeout_retries; - - /*! - * Number of trials to get a frame acknowledged - */ - uint8_t ack_timeout_retry_counter; - - /*! - * Maximum number of trials for the Join Request - */ - uint8_t max_join_request_trials; - - /*! - * Number of trials for the Join Request - */ - uint8_t join_request_trial_counter; - - /*! - * Mac keys - */ - loramac_keys keys; - - /*! - * Device nonce is a random value extracted by issuing a sequence of RSSI - * measurements - */ - uint16_t dev_nonce; - - /*! - * Network ID ( 3 bytes ) - */ - uint32_t net_id; - - /*! - * Mote Address - */ - uint32_t dev_addr; - - /*! - * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. - * Only the 16 LSB bits are sent - */ - uint32_t ul_frame_counter; - - /*! - * LoRaMAC frame counter. Each time a packet is received the counter is incremented. - * Only the 16 LSB bits are received - */ - uint32_t dl_frame_counter; - - /*! - * Counts the number of missed ADR acknowledgements - */ - uint32_t adr_ack_counter; - - /*! - * LoRaMac reception windows delay - * \remark normal frame: RxWindowXDelay = ReceiveDelayX - Offset - * join frame : RxWindowXDelay = JoinAcceptDelayX - Offset - */ - uint32_t rx_window1_delay; - uint32_t rx_window2_delay; - - /*! - * Timer objects and stored values - */ - lorawan_timers timers; - - /*! - * LoRaMac parameters - */ - lora_mac_system_params_t sys_params; - - /*! - * Receive Window configurations for PHY layer - */ - rx_config_params_t rx_window1_config; - rx_config_params_t rx_window2_config; - - /*! - * Multicast channels linked list - */ - multicast_params_t *multicast_channels; - -} loramac_protocol_params; - -#endif /* LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ */