| @@ -0,0 +1,28 @@ | |||
| lst/ | |||
| obj/ | |||
| bin/ | |||
| build/ | |||
| tmp/ | |||
| *.bin | |||
| .kdev4 | |||
| *.log | |||
| *.dep | |||
| *.uvgui.* | |||
| *.uvgui_*.bak | |||
| *.uvguix.* | |||
| *.uvguix_*.bak | |||
| *_uvopt.bak | |||
| *_uvoptx.bak | |||
| *_uvproj.bak | |||
| *_uvprojx.bak | |||
| *.ctx | |||
| *.dbi | |||
| *.xdb | |||
| *.svn | |||
| *.pbxproj | |||
| *.cogui | |||
| *.comarker | |||
| .directory | |||
| .vscode/launch.json | |||
| .cmaketools.json | |||
| ipch/ | |||
| @@ -0,0 +1,6 @@ | |||
| [submodule "src/radio/lr1110/lr1110_driver"] | |||
| path = src/radio/lr1110/lr1110_driver | |||
| url = https://github.com/Lora-net/lr1110_driver.git | |||
| [submodule "src/peripherals/atecc608a-tnglora-se/cryptoauthlib"] | |||
| path = src/peripherals/atecc608a-tnglora-se/cryptoauthlib | |||
| url = https://github.com/MicrochipTech/cryptoauthlib | |||
| @@ -0,0 +1,18 @@ | |||
| { | |||
| "configurations": [ | |||
| { | |||
| "name": "ARM", | |||
| "compileCommands": "${workspaceRoot}/build/compile_commands.json", | |||
| "intelliSenseMode": "clang-x64", | |||
| "browse": { | |||
| "path": [ | |||
| "${workspaceFolder}" | |||
| ] | |||
| }, | |||
| "cStandard": "c11", | |||
| "cppStandard": "c++17", | |||
| "configurationProvider": "ms-vscode.cmake-tools" | |||
| } | |||
| ], | |||
| "version": 4 | |||
| } | |||
| @@ -0,0 +1,83 @@ | |||
| // Place your settings in this file to overwrite default and user settings. | |||
| { | |||
| "cmake.configureSettings": { | |||
| // In case your GNU ARM-Toolchain is not installed under the default | |||
| // path: | |||
| // Windows : No default path. Specify the path where the | |||
| // toolchain is installed. i.e: | |||
| // "C:/PROGRA~2/GNUTOO~1/92019-~1". | |||
| // Linux : /usr | |||
| // OSX : /usr/local | |||
| // It is required to uncomment and to fill the following line. | |||
| //"TOOLCHAIN_PREFIX":"/path/to/toolchain", | |||
| // In case your OpenOCD is not installed under the default path: | |||
| // Windows : C:/openocd/bin/openocd.exe | |||
| // Linux : /usr/bin/openocd | |||
| // OSX : /usr/local/bin/openocd | |||
| // Please uncomment the following line and fill it accordingly. | |||
| //"OPENOCD_BIN":"C:/openocd/bin/openocd.exe", | |||
| // Specifies the path to the CMAKE toolchain file. | |||
| "CMAKE_TOOLCHAIN_FILE":"cmake/toolchain-arm-none-eabi.cmake", | |||
| // Determines the application. You can choose between: | |||
| // LoRaMac (Default), ping-pong, rx-sensi, tx-cw. | |||
| "APPLICATION":"LoRaMac", | |||
| // Select LoRaMac sub project. You can choose between: | |||
| // periodic-uplink-lpp, fuota-test-01. | |||
| "SUB_PROJECT":"periodic-uplink-lpp", | |||
| // Switch for Class B support of LoRaMac: | |||
| "CLASSB_ENABLED":"ON", | |||
| // Select the active region for which the stack will be initialized. | |||
| // You can choose between: | |||
| // LORAMAC_REGION_EU868, LORAMAC_REGION_US915, .. | |||
| "ACTIVE_REGION":"LORAMAC_REGION_EU868", | |||
| // Select the type of modulation, applicable to the ping-pong or | |||
| // rx-sensi applications. You can choose between: | |||
| // LORA or FSK | |||
| "MODULATION":"LORA", | |||
| // Target board, the following boards are supported: | |||
| // NAMote72, NucleoL073 (Default), NucleoL152, NucleoL476, SAMR34, SKiM880B, SKiM980A, SKiM881AXL, B-L072Z-LRWAN1. | |||
| "BOARD":"NucleoL073", | |||
| // MBED Radio shield selection. (Applies only to Nucleo platforms) | |||
| // The following shields are supported: | |||
| // SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS(Default), SX1262MBXCAS, SX1262MBXDAS, LR1110MB1XXS. | |||
| "MBED_RADIO_SHIELD":"SX1261MBXBAS", | |||
| // Secure element type selection the following are supported | |||
| // SOFT_SE(Default), LR1110_SE, ATECC608A_TNGLORA_SE | |||
| "SECURE_ELEMENT":"SOFT_SE", | |||
| // Secure element is pre-provisioned | |||
| "SECURE_ELEMENT_PRE_PROVISIONED":"ON", | |||
| // Region support activation, Select the ones you want to support. | |||
| // By default only REGION_EU868 support is enabled. | |||
| "REGION_EU868":"ON", | |||
| "REGION_US915":"OFF", | |||
| "REGION_CN779":"OFF", | |||
| "REGION_EU433":"OFF", | |||
| "REGION_AU915":"OFF", | |||
| "REGION_CN470":"OFF", | |||
| "REGION_AS923":"OFF", | |||
| "REGION_KR920":"OFF", | |||
| "REGION_IN865":"OFF", | |||
| "REGION_RU864":"OFF", | |||
| // Default channel plan for region AS923. Possible selections: | |||
| // CHANNEL_PLAN_GROUP_AS923_1, CHANNEL_PLAN_GROUP_AS923_2, CHANNEL_PLAN_GROUP_AS923_3, CHANNEL_PLAN_GROUP_AS923_1_JP | |||
| "REGION_AS923_DEFAULT_CHANNEL_PLAN":"CHANNEL_PLAN_GROUP_AS923_1", | |||
| // Default channel plan for region CN470. Possible selections: | |||
| // CHANNEL_PLAN_20MHZ_TYPE_A, CHANNEL_PLAN_20MHZ_TYPE_B, CHANNEL_PLAN_26MHZ_TYPE_A, CHANNEL_PLAN_26MHZ_TYPE_B | |||
| "REGION_CN470_DEFAULT_CHANNEL_PLAN":"CHANNEL_PLAN_20MHZ_TYPE_A" | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(loramac-node) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) | |||
| @@ -0,0 +1,24 @@ | |||
| Revised BSD License | |||
| Copyright Semtech Corporation 2013. 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 CORPORATION 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. | |||
| @@ -0,0 +1,395 @@ | |||
| # LoRaWAN end-device stack implementation and example projects | |||
| ______ _ | |||
| / _____) _ | | | |||
| ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| _____) ) ____| | | || |_| ____( (___| | | | | |||
| (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| (C)2013-2020 Semtech | |||
| ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| embedded.connectivity.solutions=============== | |||
| ## Introduction | |||
| The aim of this project is to show an example of an end-device LoRaWAN stack implementation. | |||
| This project has 2 active branches in place. | |||
| | Branch | L2 spec | RP spec | Tag/Milestone | Class | Comments | | |||
| | ------------- |:-------------:|:---------:|:---------:|:---------:|:--------------| | |||
| | | [1.0.4](https://lora-alliance.org/resource-hub/lorawan-104-specification-package) | [2-1.0.1](https://lora-alliance.org/sites/default/files/2020-02/rp_2-1.0.1.pdf) | [v4.5.1](https://github.com/Lora-net/LoRaMac-node/releases/tag/v4.5.1) | A/B/C | LoRaWAN L2 1.0.4 - **_Released_** | | |||
| | | [1.0.3](https://lora-alliance.org/resource-hub/lorawanr-specification-v103) | [v1.0.3revA](https://www.lora-alliance.org/resource-hub/lorawanr-regional-parameters-v103reva) | [v4.4.7](https://github.com/Lora-net/LoRaMac-node/releases/tag/v4.4.7) | A/B/C | LoRaWAN L2 1.0.3 - **_Released_ (last release based on 1.0.3)** | | |||
| | [master](https://github.com/Lora-net/LoRaMac-node/tree/master) | [1.0.4](https://lora-alliance.org/resource-hub/lorawan-104-specification-package) | [2-1.0.1](https://lora-alliance.org/sites/default/files/2020-02/rp_2-1.0.1.pdf) | [M4.5.2](https://github.com/Lora-net/LoRaMac-node/milestone/9) | A/B/C | LoRaWAN L2 1.0.4 | | |||
| | [develop](https://github.com/Lora-net/LoRaMac-node/tree/develop) | [1.0.4](https://lora-alliance.org/resource-hub/lorawan-104-specification-package) / [1.1.1](https://lora-alliance.org/resource-hub/lorawanr-specification-v11) | [2-1.0.1](https://lora-alliance.org/sites/default/files/2020-02/rp_2-1.0.1.pdf) | [M 4.6.0](https://github.com/Lora-net/LoRaMac-node/milestone/3) | A/B/C | LoRaWAN L2 1.0.4 / 1.1.1 | | |||
| This project fully implements ClassA, ClassB and ClassC end-device classes and it also provides SX1272/73, SX1276/77/78/79, SX1261/2 and LR1110 radio drivers. | |||
| For each currently supported platform example applications are provided. | |||
| * **LoRaMac/fuota-test-01**: FUOTA test scenario 01 end-device example application. (Based on provided application common packages) | |||
| * **LoRaMac/periodic-uplink-lpp**: ClassA/B/C end-device example application. Periodically uplinks a frame using the Cayenne LPP protocol. (Based on provided application common packages) | |||
| * **ping-pong**: Point to point RF link example application. | |||
| * **rx-sensi**: Example application useful to measure the radio sensitivity level using an RF generator. | |||
| * **tx-cw**: Example application to show how to generate an RF Continuous Wave transmission. | |||
| **Note**: *Each LoRaWAN application example (LoRaMac/\*) includes an implementation of the LoRa-Alliance; LoRaWAN certification protocol.* | |||
| **Note**: *The LoRaWAN stack API documentation can be found at: http://stackforce.github.io/LoRaMac-doc/* | |||
| ## Supported platforms | |||
| This project currently provides support for the below platforms. | |||
| This project can be ported to other platforms using different MCU than the ones currently supported. | |||
| The [Porting Guide](https://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/_p_o_r_t_i_n_g__g_u_i_d_e.html) document provides guide lines on how to port the project to other platforms. | |||
| * NAMote72 | |||
| * [NAMote72 platform documentation](doc/NAMote72-platform.md) | |||
| * NucleoLxxx - Discovery kit | |||
| * [NucleoLxxx and Discovery kit platforms documentation](doc/NucleoLxxx-platform.md) | |||
| * SKiM880B, SKiM980A, SKiM881AXL | |||
| * [SKiM88xx platforms documentation](doc/SKiM88xx-platform.md) | |||
| * SAMR34 | |||
| * [SAMR34 platform documentation](doc/SAMR34-platform.md) | |||
| ## Getting Started | |||
| ### Prerequisites | |||
| Please follow instructions provided by [Development environment](doc/development-environment.md) document. | |||
| ### Cloning the repository | |||
| Clone the repository from GitHub | |||
| ```bash | |||
| $ git clone https://github.com/lora-net/loramac-node.git loramac-node | |||
| ``` | |||
| LoRaMac-node project contains Git submodules that must be initialized | |||
| ```bash | |||
| $ cd loramac-node | |||
| $ git submodule update --init | |||
| ``` | |||
| ### Secure-element commissioning | |||
| This project currently supports 3 different secure-elements `soft-se`, `lr1110-se` | |||
| and `atecc608a-tnglora-se` implementations. | |||
| In order to personalize the MCU binary file with LoRaWAN EUIs or/and AES128 keys | |||
| one must follow the instructions provided by [soft-se](####soft-se), | |||
| [lr1110-se](####lr1110-se) and [atecc608a-tnglora-se](####atecc608a-tnglora-se) chapters | |||
| #### soft-se | |||
| *soft-se* is a pure software emulation of a secure-element. It means that everything is located on the host MCU memories. The `DevEUI`, `JoinEUI` and `AES128 keys` may be stored on a non-volatile memory through dedicated APIs. | |||
| In order to update the end-device identity (`DevEUI`, `JoinEUI` and `AES128 keys`) one must update the `se-identity.h` file located under `./src/peripherals/soft-se/` directory. | |||
| **Note:** In previous versions of this project this was done inside `Commissioning.h` files located under each provided example directory. | |||
| #### lr1110-se | |||
| *lr1110-se* abstraction implementation handles all the required exchanges with the LR1110 radio crypto-engine. | |||
| All LR1110 radio chips are pre-provisioned out of factory in order to be used with [LoRa Cloud Device Join Service](https://www.loracloud.com/documentation/join_service). | |||
| In case other Join Servers are to be used the `DevEUI`, `Pin`, `JoinEUI` and `AES128 keys` can be updated by following the instructions provided on chapter "13. LR1110 Provisioning" of the [LR1110 User Manual](https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000Q2PM/KGm1YHDoHhtaicNYHCIAnh0CbG3yodEuWWJ2WrFRafM). | |||
| When the compile option `SECURE_ELEMENT_PRE_PROVISIONED` is set to `ON` the *lr1110-se* will use the factory provisioned data (`DevEUI`, `JoinEUI` and `AES128 keys`). | |||
| When the compile option `SECURE_ELEMENT_PRE_PROVISIONED` is set to `OFF` the *lr1110-se* has to be provisioned by following one of the methods described on chapter "13. LR1110 Provisioning" of the [LR1110 User Manual](https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000Q2PM/KGm1YHDoHhtaicNYHCIAnh0CbG3yodEuWWJ2WrFRafM). | |||
| The `DevEUI`, `Pin` and `JoinEUI` can be changed by editing the `se-identity.h` file located in `./src/peripherals/lr1110-se/` directory. | |||
| #### atecc608a-tnglora-se | |||
| The *atecc608a-tnglora-se* abstraction implementation handles all the required exchanges with the ATECC608A-TNGLORA secure-element. | |||
| ATECC608A-TNGLORA secure-element is always pre-provisioned and its contents can't be changed. | |||
| ### Building Process | |||
| #### Command line | |||
| **periodic-uplink-lpp** example for NucleoL476 platform with LR1110MB1DIS MBED shield and using LR1110 pre-provisioned secure-element | |||
| ```bash | |||
| $ mkdir build | |||
| $ cd build | |||
| $ cmake -DCMAKE_BUILD_TYPE=Release \ | |||
| -DTOOLCHAIN_PREFIX="<replace by toolchain path>" \ | |||
| -DCMAKE_TOOLCHAIN_FILE="../cmake/toolchain-arm-none-eabi.cmake" \ | |||
| -DAPPLICATION="LoRaMac" \ | |||
| -DSUB_PROJECT="periodic-uplink-lpp" \ | |||
| -DCLASSB_ENABLED="ON" \ | |||
| -DACTIVE_REGION="LORAMAC_REGION_EU868" \ | |||
| -DREGION_EU868="ON" \ | |||
| -DREGION_US915="OFF" \ | |||
| -DREGION_CN779="OFF" \ | |||
| -DREGION_EU433="OFF" \ | |||
| -DREGION_AU915="OFF" \ | |||
| -DREGION_AS923="OFF" \ | |||
| -DREGION_CN470="OFF" \ | |||
| -DREGION_KR920="OFF" \ | |||
| -DREGION_IN865="OFF" \ | |||
| -DREGION_RU864="OFF" \ | |||
| -DBOARD="NucleoL476" \ | |||
| -DMBED_RADIO_SHIELD="LR1110MB1XXS" \ | |||
| -DSECURE_ELEMENT="LR1110_SE" \ | |||
| -DSECURE_ELEMENT_PRE_PROVISIONED="ON" \ | |||
| -DUSE_RADIO_DEBUG="ON" .. | |||
| $ make | |||
| ``` | |||
| **ping-pong** example using LoRa modulation for NucleoL476 platform with LR1110MB1DIS MBED shield | |||
| ```bash | |||
| $ mkdir build | |||
| $ cd build | |||
| $ cmake -DCMAKE_BUILD_TYPE=Release \ | |||
| -DTOOLCHAIN_PREFIX="<replace by toolchain path>" \ | |||
| -DCMAKE_TOOLCHAIN_FILE="../cmake/toolchain-arm-none-eabi.cmake" \ | |||
| -DAPPLICATION="ping-pong" \ | |||
| -DMODULATION:"LORA" \ | |||
| -DREGION_EU868="ON" \ | |||
| -DREGION_US915="OFF" \ | |||
| -DREGION_CN779="OFF" \ | |||
| -DREGION_EU433="OFF" \ | |||
| -DREGION_AU915="OFF" \ | |||
| -DREGION_AS923="OFF" \ | |||
| -DREGION_CN470="OFF" \ | |||
| -DREGION_KR920="OFF" \ | |||
| -DREGION_IN865="OFF" \ | |||
| -DREGION_RU864="OFF" \ | |||
| -DBOARD="NucleoL476" \ | |||
| -DMBED_RADIO_SHIELD="LR1110MB1XXS" \ | |||
| -DUSE_RADIO_DEBUG="ON" .. | |||
| $ make | |||
| ``` | |||
| #### VSCode | |||
| **periodic-uplink-lpp** example for NucleoL476 platform with LR1110MB1DIS MBED shield and using LR1110 pre-provisioned secure-element | |||
| * Please edit .vscode/settings.json file | |||
| <details> | |||
| <summary>Click to expand!</summary> | |||
| <p> | |||
| ```json | |||
| // Place your settings in this file to overwrite default and user settings. | |||
| { | |||
| "cmake.configureSettings": { | |||
| // In case your GNU ARM-Toolchain is not installed under the default | |||
| // path: | |||
| // Windows : No default path. Specify the path where the | |||
| // toolchain is installed. i.e: | |||
| // "C:/PROGRA~2/GNUTOO~1/92019-~1". | |||
| // Linux : /usr | |||
| // OSX : /usr/local | |||
| // It is required to uncomment and to fill the following line. | |||
| "TOOLCHAIN_PREFIX":"/path/to/toolchain", | |||
| // In case your OpenOCD is not installed under the default path: | |||
| // Windows : C:/openocd/bin/openocd.exe | |||
| // Linux : /usr/bin/openocd | |||
| // OSX : /usr/local/bin/openocd | |||
| // Please uncomment the following line and fill it accordingly. | |||
| //"OPENOCD_BIN":"C:/openocd/bin/openocd.exe", | |||
| // Specifies the path to the CMAKE toolchain file. | |||
| "CMAKE_TOOLCHAIN_FILE":"cmake/toolchain-arm-none-eabi.cmake", | |||
| // Determines the application. You can choose between: | |||
| // LoRaMac (Default), ping-pong, rx-sensi, tx-cw. | |||
| "APPLICATION":"LoRaMac", | |||
| // Select LoRaMac sub project. You can choose between: | |||
| // periodic-uplink-lpp, fuota-test-01. | |||
| "SUB_PROJECT":"periodic-uplink-lpp", | |||
| // Switch for Class B support of LoRaMac: | |||
| "CLASSB_ENABLED":"ON", | |||
| // Select the active region for which the stack will be initialized. | |||
| // You can choose between: | |||
| // LORAMAC_REGION_EU868, LORAMAC_REGION_US915, .. | |||
| "ACTIVE_REGION":"LORAMAC_REGION_EU868", | |||
| // Select the type of modulation, applicable to the ping-pong or | |||
| // rx-sensi applications. You can choose between: | |||
| // LORA or FSK | |||
| "MODULATION":"LORA", | |||
| // Target board, the following boards are supported: | |||
| // NAMote72, NucleoL073 (Default), NucleoL152, NucleoL476, SAMR34, SKiM880B, SKiM980A, SKiM881AXL, B-L072Z-LRWAN1. | |||
| "BOARD":"NucleoL476", | |||
| // MBED Radio shield selection. (Applies only to Nucleo platforms) | |||
| // The following shields are supported: | |||
| // SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS(Default), SX1262MBXCAS, SX1262MBXDAS, LR1110MB1XXS. | |||
| "MBED_RADIO_SHIELD":"LR1110MB1XXS", | |||
| // Secure element type selection the following are supported | |||
| // SOFT_SE(Default), LR1110_SE, ATECC608A_TNGLORA_SE | |||
| "SECURE_ELEMENT":"LR1110_SE", | |||
| // Secure element is pre-provisioned | |||
| "SECURE_ELEMENT_PRE_PROVISIONED":"ON", | |||
| // Region support activation, Select the ones you want to support. | |||
| // By default only REGION_EU868 support is enabled. | |||
| "REGION_EU868":"ON", | |||
| "REGION_US915":"OFF", | |||
| "REGION_CN779":"OFF", | |||
| "REGION_EU433":"OFF", | |||
| "REGION_AU915":"OFF", | |||
| "REGION_AS923":"OFF", | |||
| "REGION_CN470":"OFF", | |||
| "REGION_KR920":"OFF", | |||
| "REGION_IN865":"OFF", | |||
| "REGION_RU864":"OFF", | |||
| "USE_RADIO_DEBUG":"ON" | |||
| } | |||
| } | |||
| ``` | |||
| </p> | |||
| </details> | |||
| * Click on "CMake: Debug: Ready" and select build type Debug or Release. | |||
|  | |||
| * Wait for configuration process to finish | |||
| * Click on "Build" to build the project. | |||
|  | |||
| * Wait for build process to finish | |||
| * Binary files will be available under `./build/src/apps/LoRaMac/` | |||
| * LoRaMac-periodic-uplink-lpp - elf format | |||
| * LoRaMac-periodic-uplink-lpp.bin - binary format | |||
| * LoRaMac-periodic-uplink-lpp.hex - hex format | |||
| **ping-pong** example using LoRa modulation for NucleoL476 platform with LR1110MB1DIS MBED shield | |||
| * Please edit .vscode/settings.json file | |||
| <details> | |||
| <summary>Click to expand!</summary> | |||
| <p> | |||
| ```json | |||
| // Place your settings in this file to overwrite default and user settings. | |||
| { | |||
| "cmake.configureSettings": { | |||
| // In case your GNU ARM-Toolchain is not installed under the default | |||
| // path: | |||
| // Windows : No default path. Specify the path where the | |||
| // toolchain is installed. i.e: | |||
| // "C:/PROGRA~2/GNUTOO~1/92019-~1". | |||
| // Linux : /usr | |||
| // OSX : /usr/local | |||
| // It is required to uncomment and to fill the following line. | |||
| "TOOLCHAIN_PREFIX":"/path/to/toolchain", | |||
| // In case your OpenOCD is not installed under the default path: | |||
| // Windows : C:/openocd/bin/openocd.exe | |||
| // Linux : /usr/bin/openocd | |||
| // OSX : /usr/local/bin/openocd | |||
| // Please uncomment the following line and fill it accordingly. | |||
| //"OPENOCD_BIN":"C:/openocd/bin/openocd.exe", | |||
| // Specifies the path to the CMAKE toolchain file. | |||
| "CMAKE_TOOLCHAIN_FILE":"cmake/toolchain-arm-none-eabi.cmake", | |||
| // Determines the application. You can choose between: | |||
| // LoRaMac (Default), ping-pong, rx-sensi, tx-cw. | |||
| "APPLICATION":"ping-pong", | |||
| // Select LoRaMac sub project. You can choose between: | |||
| // periodic-uplink-lpp, fuota-test-01. | |||
| "SUB_PROJECT":"periodic-uplink-lpp", | |||
| // Switch for Class B support of LoRaMac: | |||
| "CLASSB_ENABLED":"ON", | |||
| // Select the active region for which the stack will be initialized. | |||
| // You can choose between: | |||
| // LORAMAC_REGION_EU868, LORAMAC_REGION_US915, .. | |||
| "ACTIVE_REGION":"LORAMAC_REGION_EU868", | |||
| // Select the type of modulation, applicable to the ping-pong or | |||
| // rx-sensi applications. You can choose between: | |||
| // LORA or FSK | |||
| "MODULATION":"LORA", | |||
| // Target board, the following boards are supported: | |||
| // NAMote72, NucleoL073 (Default), NucleoL152, NucleoL476, SAMR34, SKiM880B, SKiM980A, SKiM881AXL, B-L072Z-LRWAN1. | |||
| "BOARD":"NucleoL476", | |||
| // MBED Radio shield selection. (Applies only to Nucleo platforms) | |||
| // The following shields are supported: | |||
| // SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS(Default), SX1262MBXCAS, SX1262MBXDAS, LR1110MB1XXS. | |||
| "MBED_RADIO_SHIELD":"SX1261MBXBAS", | |||
| // Secure element type selection the following are supported | |||
| // SOFT_SE(Default), LR1110_SE, ATECC608A_TNGLORA_SE | |||
| "SECURE_ELEMENT":"SOFT_SE", | |||
| // Secure element is pre-provisioned | |||
| "SECURE_ELEMENT_PRE_PROVISIONED":"ON", | |||
| // Region support activation, Select the ones you want to support. | |||
| // By default only REGION_EU868 support is enabled. | |||
| "REGION_EU868":"ON", | |||
| "REGION_US915":"OFF", | |||
| "REGION_CN779":"OFF", | |||
| "REGION_EU433":"OFF", | |||
| "REGION_AU915":"OFF", | |||
| "REGION_AS923":"OFF", | |||
| "REGION_CN470":"OFF", | |||
| "REGION_KR920":"OFF", | |||
| "REGION_IN865":"OFF", | |||
| "REGION_RU864":"OFF", | |||
| "USE_RADIO_DEBUG":"ON" | |||
| } | |||
| } | |||
| ``` | |||
| </p> | |||
| </details> | |||
| * Click on "CMake: Debug: Ready" and select build type Debug or Release. | |||
|  | |||
| * Wait for configuration process to finish | |||
| * Click on "Build" to build the project. | |||
|  | |||
| * Wait for build process to finish | |||
| * Binary files will be available under `./build/src/apps/ping-pong/` | |||
| * ping-pong - elf format | |||
| * ping-pong.bin - binary format | |||
| * ping-pong.hex - hex format | |||
| ## Acknowledgments | |||
| * The mbed (https://mbed.org/) project was used at the beginning as source of | |||
| inspiration. | |||
| * This program uses the AES algorithm implementation (http://www.gladman.me.uk/) by Brian Gladman. | |||
| * This program uses the CMAC algorithm implementation | |||
| (http://www.cse.chalmers.se/research/group/dcs/masters/contikisec/) by Lander Casado, Philippas Tsigas. | |||
| * [The Things Industries](https://www.thethingsindustries.com/) for providing | |||
| Microchip/Atmel SAMR34 platform and ATECC608A-TNGLORA secure-element support. | |||
| * Tencent Blade Team for security breach findings and solving propositions. | |||
| @@ -0,0 +1,16 @@ | |||
| # Security Policy | |||
| ## Supported Versions | |||
| Vulnerability fixes will always be applied on [develop](https://github.com/Lora-net/LoRaMac-node/tree/develop) branch and included in next release. | |||
| We may consider to hotfix the most recent release depending on the circumstances. Older releases will not be hotfixed. | |||
| | Version | Supported | | |||
| | ------- | ------------------ | | |||
| | [develop](https://github.com/Lora-net/LoRaMac-node/tree/develop) | :white_check_mark: | | |||
| | [latest release](https://github.com/Lora-net/LoRaMac-node/releases/latest) | :question: | | |||
| | older releases | :x: | | |||
| ## Reporting a Vulnerability | |||
| Please report security concerns, perceived or implemented vulnerabilities in the source code of this project to: [LoRa-Net@semtech.com](mailto:LoRa-Net@semtech.com) | |||
| @@ -0,0 +1,50 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## | |||
| ## CMake arm-none-eabi binutils integration and helper functions | |||
| ## | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set tools | |||
| #--------------------------------------------------------------------------------------- | |||
| set(CMAKE_OBJCOPY ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-objcopy${TOOLCHAIN_EXT}) | |||
| set(CMAKE_OBJDUMP ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-objdump${TOOLCHAIN_EXT}) | |||
| set(CMAKE_SIZE ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-size${TOOLCHAIN_EXT}) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Prints the section sizes | |||
| #--------------------------------------------------------------------------------------- | |||
| function(print_section_sizes TARGET) | |||
| add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_SIZE} ${TARGET}) | |||
| endfunction() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Creates output in hex format | |||
| #--------------------------------------------------------------------------------------- | |||
| function(create_hex_output TARGET) | |||
| add_custom_target(${TARGET}.hex ALL DEPENDS ${TARGET} COMMAND ${CMAKE_OBJCOPY} -Oihex ${TARGET} ${TARGET}.hex) | |||
| endfunction() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Creates output in binary format | |||
| #--------------------------------------------------------------------------------------- | |||
| function(create_bin_output TARGET) | |||
| add_custom_target(${TARGET}.bin ALL DEPENDS ${TARGET} COMMAND ${CMAKE_OBJCOPY} -Obinary ${TARGET} ${TARGET}.bin) | |||
| endfunction() | |||
| @@ -0,0 +1,101 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## Collection of functions to generate different GDB debugging configurations | |||
| ## | |||
| # Get the path of this module | |||
| set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set tools | |||
| #--------------------------------------------------------------------------------------- | |||
| set(GDB_BIN ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gdb${TOOLCHAIN_EXT}) | |||
| if(NOT OPENOCD_BIN) | |||
| if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) | |||
| set(OPENOCD_BIN "/usr/bin/openocd" CACHE STRING "OpenOCD executable") | |||
| elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) | |||
| set(OPENOCD_BIN "/usr/local/bin/openocd" CACHE STRING "OpenOCD executable") | |||
| elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) | |||
| set(OPENOCD_BIN "C:/openocd/bin/openocd.exe" CACHE STRING "OpenOCD executable") | |||
| endif() | |||
| endif() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Generates a GDB run script for debugging with STLINKv1/v2/v2-1 programmer and texane stlink tool. | |||
| # More infos check: https://github.com/texane/stlink | |||
| #--------------------------------------------------------------------------------------- | |||
| function(generate_run_gdb_stlink TARGET) | |||
| get_target_property( TARGET_NAME ${TARGET} NAME ) | |||
| configure_file(${CURRENT_MODULE_DIR}/stlink-run.gdb.in ${PROJECT_BINARY_DIR}/stlink-run.gdb @ONLY) | |||
| endfunction() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Generates a GDB run script for debugging with any supported programmer and openOCD. | |||
| #--------------------------------------------------------------------------------------- | |||
| function(generate_run_gdb_openocd TARGET) | |||
| get_target_property( TARGET_NAME ${TARGET} NAME ) | |||
| configure_file(${CURRENT_MODULE_DIR}/openocd-run.gdb.in ${PROJECT_BINARY_DIR}/openocd-run.gdb @ONLY) | |||
| endfunction() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Generates a Visual Studio Code launch configuration for debugging with openOCD. | |||
| #--------------------------------------------------------------------------------------- | |||
| function(generate_vscode_launch_openocd TARGET) | |||
| get_target_property( TARGET_NAME ${TARGET} NAME ) | |||
| # Available OpenOCD interfaces | |||
| # Use stlink-v2-1.cfg when stlink interface is built in. Otherwise use stlink-v2.cfg | |||
| set(OPENOCD_INTERFACE_LIST stlink-v2-1.cfg stlink-v2.cfg) | |||
| set(OPENOCD_INTERFACE stlink-v2.cfg CACHE STRING "Default OPENOCD Interface is stlink-v2.cfg") | |||
| set_property(CACHE OPENOCD_INTERFACE PROPERTY STRINGS ${OPENOCD_INTERFACE_LIST}) | |||
| # Available OpenOCD targets | |||
| set(OPENOCD_TARGET_LIST stm32l0.cfg stm32l1.cfg) | |||
| set(OPENOCD_TARGET stm32l1.cfg CACHE STRING "Default OPENOCD Target is stm32l1.cfg") | |||
| set_property(CACHE OPENOCD_TARGET PROPERTY STRINGS ${OPENOCD_TARGET_LIST}) | |||
| # Available OpenOCD targets | |||
| set(OPENOCD_BOARD_LIST atmel_saml21_xplained_pro.cfg ) | |||
| set(OPENOCD_BOARD atmel_saml21_xplained_pro.cfg CACHE STRING "Default OPENOCD board is atmel_saml21_xplained_pro.cfg") | |||
| set_property(CACHE OPENOCD_BOARD PROPERTY STRINGS ${OPENOCD_BOARD_LIST}) | |||
| # Set the OPENOCD_TARGET and OPENOCD_INTERFACE variables according to BOARD | |||
| if(BOARD STREQUAL NAMote72 OR BOARD STREQUAL NucleoL152) | |||
| set(OPENOCD_INTERFACE stlink-v2-1.cfg) | |||
| set(OPENOCD_TARGET stm32l1.cfg) | |||
| elseif(BOARD STREQUAL NucleoL073 OR BOARD STREQUAL B-L072Z-LRWAN1) | |||
| set(OPENOCD_INTERFACE stlink-v2-1.cfg) | |||
| set(OPENOCD_TARGET stm32l0.cfg) | |||
| elseif(BOARD STREQUAL NucleoL476) | |||
| set(OPENOCD_INTERFACE stlink-v2-1.cfg) | |||
| set(OPENOCD_TARGET stm32l4x.cfg) | |||
| elseif(BOARD STREQUAL SKiM880B OR BOARD STREQUAL SKiM980A) | |||
| set(OPENOCD_INTERFACE stlink-v2.cfg) | |||
| set(OPENOCD_TARGET stm32l1.cfg) | |||
| elseif(BOARD STREQUAL SKiM881AXL) | |||
| set(OPENOCD_INTERFACE stlink-v2.cfg) | |||
| set(OPENOCD_TARGET stm32l0.cfg) | |||
| elseif(BOARD STREQUAL SAMR34) | |||
| set(OPENOCD_INTERFACE cmsis-dap.cfg) | |||
| set(OPENOCD_TARGET at91samdXX.cfg) | |||
| endif() | |||
| configure_file(${CURRENT_MODULE_DIR}/launch.json.in ${CMAKE_SOURCE_DIR}/.vscode/launch.json @ONLY) | |||
| endfunction() | |||
| @@ -0,0 +1,40 @@ | |||
| { | |||
| "version": "0.2.0", | |||
| "configurations": [ | |||
| { | |||
| "name": "Debug-@TARGET_NAME@", | |||
| "type": "cppdbg", | |||
| "request": "launch", | |||
| "program": "${workspaceRoot}/build/src/apps/@APPLICATION@/@TARGET_NAME@", | |||
| "args": [], | |||
| "stopAtEntry": true, | |||
| "cwd": "${workspaceRoot}", | |||
| "environment": [], | |||
| "externalConsole": false, | |||
| "debugServerArgs": "-f interface/@OPENOCD_INTERFACE@ -f target/@OPENOCD_TARGET@", | |||
| "serverLaunchTimeout": 20000, | |||
| "filterStderr": true, | |||
| "filterStdout": false, | |||
| "serverStarted": "Info\\ :\\ [\\w\\d\\.]*:\\ hardware", | |||
| "setupCommands": [ | |||
| { "text": "cd ${workspaceRoot}/build" }, | |||
| { "text": "file src/apps/@APPLICATION@/@TARGET_NAME@", "description": "load file", "ignoreFailures": false}, | |||
| { "text": "target extended-remote localhost:3333", "description": "connect to target", "ignoreFailures": false }, | |||
| { "text": "monitor reset halt", "description": "perform a reset and halt the target", "ignoreFailures": false }, | |||
| { "text": "load", "description": "flash target", "ignoreFailures": false }, | |||
| { "text": "monitor reset init", "description": "perform a reset and init the target", "ignoreFailures": false }, | |||
| { "text": "set output-radix 16", "description": "set the default numeric base to 16", "ignoreFailures": false } | |||
| ], | |||
| "logging": { | |||
| "moduleLoad": true, | |||
| "trace": true, | |||
| "engineLogging": true, | |||
| "programOutput": true, | |||
| "exceptions": true | |||
| }, | |||
| "MIMode": "gdb", | |||
| "miDebuggerPath": "@GDB_BIN@", | |||
| "debugServerPath": "@OPENOCD_BIN@" | |||
| } | |||
| ] | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| file @TARGET_NAME@ | |||
| target extended-remote localhost:3333 | |||
| monitor reset halt | |||
| load | |||
| thbreak main | |||
| @@ -0,0 +1,41 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ), | |||
| ## Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017 | |||
| ## | |||
| ## | |||
| ## SAMR34 target specific CMake file | |||
| ## | |||
| if(NOT DEFINED LINKER_SCRIPT) | |||
| message(FATAL_ERROR "No linker script defined") | |||
| endif(NOT DEFINED LINKER_SCRIPT) | |||
| message("Linker script: ${LINKER_SCRIPT}") | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set compiler/linker flags | |||
| #--------------------------------------------------------------------------------------- | |||
| # Object build options | |||
| set(OBJECT_GEN_FLAGS "-Og -g -mthumb -g2 -fno-builtin -mcpu=cortex-m0plus -Wall -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize -mlong-calls") | |||
| set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") | |||
| set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++11 " CACHE INTERNAL "C++ Compiler options") | |||
| set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") | |||
| # Linker flags | |||
| set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m0plus -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map" CACHE INTERNAL "Linker options") | |||
| @@ -0,0 +1,6 @@ | |||
| file @TARGET_NAME@ | |||
| target extended localhost:4242 | |||
| monitor reset halt | |||
| shell sleep 1 | |||
| load | |||
| thbreak main | |||
| @@ -0,0 +1,40 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## | |||
| ## STM32L0 target specific CMake file | |||
| ## | |||
| if(NOT DEFINED LINKER_SCRIPT) | |||
| message(FATAL_ERROR "No linker script defined") | |||
| endif(NOT DEFINED LINKER_SCRIPT) | |||
| message("Linker script: ${LINKER_SCRIPT}") | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set compiler/linker flags | |||
| #--------------------------------------------------------------------------------------- | |||
| # Object build options | |||
| set(OBJECT_GEN_FLAGS "-Og -g -mthumb -g2 -fno-builtin -mcpu=cortex-m0plus -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize") | |||
| set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") | |||
| set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++11 " CACHE INTERNAL "C++ Compiler options") | |||
| set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") | |||
| # Linker flags | |||
| set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m0plus -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map" CACHE INTERNAL "Linker options") | |||
| @@ -0,0 +1,40 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## | |||
| ## STM32L1 target specific CMake file | |||
| ## | |||
| if(NOT DEFINED LINKER_SCRIPT) | |||
| message(FATAL_ERROR "No linker script defined") | |||
| endif(NOT DEFINED LINKER_SCRIPT) | |||
| message("Linker script: ${LINKER_SCRIPT}") | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set compiler/linker flags | |||
| #--------------------------------------------------------------------------------------- | |||
| # Object build options | |||
| set(OBJECT_GEN_FLAGS "-Og -g -mthumb -g2 -fno-builtin -mcpu=cortex-m3 -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize") | |||
| set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") | |||
| set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++11 " CACHE INTERNAL "C++ Compiler options") | |||
| set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") | |||
| # Linker flags | |||
| set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m3 -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map" CACHE INTERNAL "Linker options") | |||
| @@ -0,0 +1,40 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2018 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## | |||
| ## STM32L4 target specific CMake file | |||
| ## | |||
| if(NOT DEFINED LINKER_SCRIPT) | |||
| message(FATAL_ERROR "No linker script defined") | |||
| endif(NOT DEFINED LINKER_SCRIPT) | |||
| message("Linker script: ${LINKER_SCRIPT}") | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set compiler/linker flags | |||
| #--------------------------------------------------------------------------------------- | |||
| # Object build options | |||
| set(OBJECT_GEN_FLAGS "-Og -g -mthumb -g2 -fno-builtin -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize") | |||
| set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") | |||
| set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++11 " CACHE INTERNAL "C++ Compiler options") | |||
| set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") | |||
| # Linker flags | |||
| set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map" CACHE INTERNAL "Linker options") | |||
| @@ -0,0 +1,90 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) | |||
| ## | |||
| ## | |||
| ## CMake arm-none-eabi toolchain file | |||
| ## | |||
| # Append current directory to CMAKE_MODULE_PATH for making device specific cmake modules visible | |||
| list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) | |||
| # Target definition | |||
| set(CMAKE_SYSTEM_NAME Generic) | |||
| set(CMAKE_SYSTEM_PROCESSOR ARM) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set toolchain paths | |||
| #--------------------------------------------------------------------------------------- | |||
| set(TOOLCHAIN arm-none-eabi) | |||
| if(NOT DEFINED TOOLCHAIN_PREFIX) | |||
| if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) | |||
| set(TOOLCHAIN_PREFIX "/usr") | |||
| elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) | |||
| set(TOOLCHAIN_PREFIX "/usr/local") | |||
| elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) | |||
| message(STATUS "Please specify the TOOLCHAIN_PREFIX !\n For example: -DTOOLCHAIN_PREFIX=\"C:/Program Files/GNU Tools ARM Embedded\" ") | |||
| else() | |||
| set(TOOLCHAIN_PREFIX "/usr") | |||
| message(STATUS "No TOOLCHAIN_PREFIX specified, using default: " ${TOOLCHAIN_PREFIX}) | |||
| endif() | |||
| endif() | |||
| set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/bin) | |||
| set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/include) | |||
| set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/lib) | |||
| # Set system depended extensions | |||
| if(WIN32) | |||
| set(TOOLCHAIN_EXT ".exe" ) | |||
| else() | |||
| set(TOOLCHAIN_EXT "" ) | |||
| endif() | |||
| # Perform compiler test with static library | |||
| set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Preset some general GCC Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options for DEBUG build | |||
| # -Og enables optimizations that do not interfere with debugging | |||
| # -g produce debugging information in the operating system’s native format | |||
| set(CMAKE_C_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C Compiler options for debug build type") | |||
| set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C++ Compiler options for debug build type") | |||
| set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type") | |||
| set(CMAKE_EXE_LINKER_FLAGS_DEBUG "" CACHE INTERNAL "Linker options for debug build type") | |||
| # Options for RELEASE build | |||
| # -Os Optimize for size. -Os enables all -O2 optimizations | |||
| set(CMAKE_C_FLAGS_RELEASE "-Os" CACHE INTERNAL "C Compiler options for release build type") | |||
| set(CMAKE_CXX_FLAGS_RELEASE "-Os" CACHE INTERNAL "C++ Compiler options for release build type") | |||
| set(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "ASM Compiler options for release build type") | |||
| set(CMAKE_EXE_LINKER_FLAGS_RELEASE "" CACHE INTERNAL "Linker options for release build type") | |||
| #--------------------------------------------------------------------------------------- | |||
| # Set compilers | |||
| #--------------------------------------------------------------------------------------- | |||
| set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "C Compiler") | |||
| set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++${TOOLCHAIN_EXT} CACHE INTERNAL "C++ Compiler") | |||
| set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "ASM Compiler") | |||
| set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH}) | |||
| set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
| set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
| set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) | |||
| set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) | |||
| @@ -0,0 +1,3 @@ | |||
| # ATECC608A-TNGLORA secure element module support documents | |||
| [ATECC608A-TNGLORA](https://www.microchip.com/wwwproducts/en/ATECC608A-TNGLORA) acts as a HW secure element, see [The Things Industries reference repository](https://github.com/TheThingsIndustries/lorawan-example-atecc608a-tnglora) for further documentation and examples. | |||
| @@ -0,0 +1,3 @@ | |||
| # NAMote72 platform support documents | |||
| * [NAMote72](https://os.mbed.com/platforms/NAMote-72/) | |||
| @@ -0,0 +1,37 @@ | |||
| # NucleoLxxx platforms support documents | |||
| * [NucleoL073RZ](https://os.mbed.com/platforms/ST-Nucleo-L073RZ/) | |||
| * [NucleoL152RE](https://os.mbed.com/platforms/ST-Nucleo-L152RE/) | |||
| * [NucleoL476RG](https://os.mbed.com/platforms/ST-Nucleo-L476RG/) | |||
| The following mbed shields may be used with NucleoLxxx platforms: | |||
| * [SX1272MB2DAS](https://os.mbed.com/components/SX1272MB2xAS/) | |||
| * [SX1276MB1LAS](https://os.mbed.com/components/SX1276MB1xAS/) | |||
| * [SX1276MB1MAS](https://os.mbed.com/components/SX1276MB1xAS/) | |||
| * [SX1261MB2BAS](https://os.mbed.com/components/SX126xMB2xAS/) | |||
| * [SX1262MB2CAS](https://os.mbed.com/components/SX126xMB2xAS/) | |||
| * [LR1110MB1DIS]() | |||
| * [LR1110MB1DJS]() | |||
| * [LR1110MB1GIS]() | |||
| * [LR1110MB1GJS]() | |||
| Development kit: | |||
| * [SX126xDVK1xAS](https://os.mbed.com/components/SX126xDVK1xAS/) | |||
| * SX1261DVK1BAS uses a SX1261MB1BAS shield | |||
| * SX1262DVK1CAS uses a SX1262MB1CAS shield | |||
| * SX1262DVK1DAS uses a SX1262MB1DAS shield | |||
| * Other variants can also be used but require some adjustments | |||
| _**Note**_: The MBX abbreviation used by the shield name variables(i.e: SX1261MBXBAS) on this project means that the shields named SX126xMB1xAS (SX126xDVK1xAS development kit only) and SX126xMB2xAS (standalone shields) are supported. | |||
| * [LR1110DVK1TXKS]() | |||
| * LR1110DVK1TBKS uses a LR1110MB1DIS or LR1110MB1DJS shield | |||
| * LR1110DVK1TCKS uses a LR1110MB1DIS or LR1110MB1DJS shield | |||
| * LR1110DVK1TGKS uses a LR1110MB1GJS or LR1110MB1GJS shield | |||
| # Discovery kit platform support documents | |||
| * [B-L072Z-LRWAN1](https://os.mbed.com/platforms/ST-Discovery-LRWAN1/) | |||
| @@ -0,0 +1,5 @@ | |||
| # SAMR34 platform support documents | |||
| The supported SAMR34 platform can be evaluated via SAMR34-XPRO evaluation kit [User Guide](http://ww1.microchip.com/downloads/en/DeviceDoc/SAM-R34-Xplained-Pro-User-Guide-DS50002803C.pdf) | |||
| The SAM R34 family data sheet can be found at [SAM R34 Family Data Sheet](http://ww1.microchip.com/downloads/en/DeviceDoc/SAMR34-R35-Low-Power-LoRa-Sub-GHz-SiP-Data-Sheet-DS70005356B.pdf) | |||
| @@ -0,0 +1,6 @@ | |||
| # SKiM88xx platforms support documents | |||
| The supported SKiM88xx platforms are: | |||
| 1. [SK-iM880B - Long Range Radio Starter Kit](https://wireless-solutions.de/products/starterkits/sk-im880b.html) | |||
| 2. [SK-iM980A - Long Range Radio Starter Kit](https://wireless-solutions.de/products/long-range-radio/im980a.html) | |||
| 3. [SK-iM881A-XL - Long Range Radio Starter Kit](https://wireless-solutions.de/products/long-range-radio/im881a-xl.html) | |||
| @@ -0,0 +1,260 @@ | |||
| # Introduction | |||
| This project uses CMake and the GNU ARM-Toolchain as build system and GDB/OpenOCD are used for debugging purposes. | |||
| By using these tools the development environment is platform agnostic and independent of chip manufacturer specific Integrated Development Environments. | |||
| It allows to build the project either by using a command line terminal or by using IDE's like [VSCode](#vscode) or [KDevelop](#kdevelop). | |||
| # Prerequisites | |||
| * CMake >= 3.6 | |||
| * GNU/Linux: | |||
| * Ubuntu 16.04/ Linux Mint 18: Since the official repository version is too old, one can use e.g. [PPA](https://launchpad.net/~adrozdoff/+archive/ubuntu/cmake) | |||
| * Linux Arch: `pacman -S cmake` | |||
| * Windows: | |||
| * [CMake Download](https://cmake.org/download/) | |||
| **Note**: Please use the latest full release and ensure that CMake path is added to the system path variable. (On Windows 10 search for _Environment Variables_ at start menu and add your CMake installation path e.g. `C:\Program Files\CMake\bin` to `Path` variable ) | |||
| * OSX: | |||
| * Homebrew: `brew install cmake` | |||
| * GNU ARM-Toolchain | |||
| * GNU/Linux: | |||
| * Ubuntu 16.04/ Linux Mint 18: Since the official repository version is too old, one can use e.g. [PPA](https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa) | |||
| * Ubuntu 18.04: the toolchain has been updated but there is a bug with [`libnewlib`](https://github.com/bbcmicrobit/micropython/issues/514#issuecomment-404759614) causing the linker to fail. `sudo apt install gcc-arm-none-eabi` | |||
| * Linux Arch: `pacman -S arm-none-eabi-gcc arm-none-eabi-newlib` | |||
| * Windows: | |||
| * [GNU Arm Embedded Toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm) | |||
| * The Make utility is also required, one can use e.g. [MSYS2](http://www.msys2.org) or [MinGW](http://mingw.org/) | |||
| * With MSYS2: | |||
| * Follow the installation instructions provided by them. | |||
| * Install MinGW Make with `pacman -S mingw-w64-x86_64-make`. | |||
| **Note**: Please ensure that both paths are added to the system PATH variable. Add for example: `C:\msys64\mingw64\bin` and `C:\Program Files (x86)\GNU Tools ARM Embedded\6 2017-q2-update\bin` to `Path` variable. | |||
| * OSX: | |||
| * Homebrew: `brew tap ARMmbed/homebrew-formulae && brew install arm-none-eabi-gcc` | |||
| * OpenOCD | |||
| * GNU/Linux: | |||
| * Ubuntu 16.04/ Linux Mint 18: `apt-get install openocd` | |||
| * Linux Arch: `pacman -S openocd` | |||
| * Windows: | |||
| * Unofficial binary packages are available [here](http://openocd.org/getting-openocd/) for download | |||
| **Note**: The debug configuration for [VSCode](#vscode) will assume that OpenOCD is installed under `C:/openocd`. If it is not the case one must change the `OPENOCD_BIN` variable according to right location. | |||
| * OSX: | |||
| * Homebrew: `brew install openocd` | |||
| # Commandline build instructions | |||
| 1. Go to root directory of the project | |||
| `cd path/to/project/directory` | |||
| 2. Create a directory named 'build' | |||
| `mkdir build` | |||
| 3. Go to the created `build` directory | |||
| `cd build` | |||
| 4. run | |||
| `cmake -DCMAKE_TOOLCHAIN_FILE="cmake/toolchain-arm-none-eabi.cmake" ..` | |||
| **Note**: If the GNU ARM-Toolchain is not installed under the default path (GNU Linux:`/usr`, Mac OS `/usr/local`) a prefix has to be provided: | |||
| `cmake -DCMAKE_TOOLCHAIN_FILE="cmake/toolchain-arm-none-eabi.cmake" -DTOOLCHAIN_PREFIX="/path/to/the/toolchain" ..` | |||
| For Windows platforms the prefix has to be provided anyway and additionally the CMake Generator for MinGW Makefiles has to be chosen: | |||
| `cmake -DCMAKE_TOOLCHAIN_FILE="cmake/toolchain-arm-none-eabi.cmake" -DTOOLCHAIN_PREFIX="/path/to/the/toolchain" -G "MinGW Makefiles" ..` | |||
| ## Available configuration options for CMake | |||
| The possibility to choose the application, target board and more options can be done using the provided configuration options. | |||
| These configuration options can be set through additional commandline parameters, for example: | |||
| `cmake -DCMAKE_TOOLCHAIN_FILE="cmake/toolchain-arm-none-eabi.cmake" -DAPPLICATION="LoRaMac" -DSUB_PROJECT="periodic-uplink-lpp" ..` | |||
| Alternatively one can use a graphical interface to configure CMake, drop down menus and check boxes will provide to the user the possible options. | |||
| * CMake QT GUI with `cmake-gui ..` | |||
| * CMake curses interface with `ccmake ..` | |||
| ### Options that can be choose by the user | |||
| * `APPLICATION` - Application example choice. | |||
| The possible choices are: | |||
| * LoRaMac (Default) | |||
| * ping-pong | |||
| * rx-sensi | |||
| * tx-cw | |||
| * `SUB_PROJECT` - LoRaMac sub project example choice. | |||
| **Note**: Only applicable to LoRaMac `APPLICATION` choice. | |||
| The possible choices are: | |||
| * periodic-uplink-lpp | |||
| * fuota-test-01 | |||
| * `ACTIVE_REGION` - Active region for which the stack will be initialized. | |||
| **Note**: Only applicable to LoRaMac `APPLICATION` choice. | |||
| The possible choices are: | |||
| * LORAMAC_REGION_EU868 | |||
| * LORAMAC_REGION_US915 | |||
| * LORAMAC_REGION_CN779 | |||
| * LORAMAC_REGION_EU433 | |||
| * LORAMAC_REGION_AU915 | |||
| * LORAMAC_REGION_AS923 | |||
| * LORAMAC_REGION_CN470 | |||
| * LORAMAC_REGION_KR920 | |||
| * LORAMAC_REGION_IN865 | |||
| * LORAMAC_REGION_RU864 | |||
| * `MODULATION` - Type of modulation choice. | |||
| **Note**: Only applicable to ping-pong or rx-sensi `APPLICATION` choice. | |||
| The possible choices are: | |||
| * LORA | |||
| * FSK | |||
| * `USE_DEBUGGER`- Enables debugger support. (Default ON) | |||
| * `BOARD` - Target board choice. | |||
| The possible choices are: | |||
| * NAMote72 | |||
| * NucleoL073 (default) | |||
| * NucleoL152 | |||
| * NucleoL476 | |||
| * SAMR34 | |||
| * SKiM880B | |||
| * SKiM980A | |||
| * SKiM881AXL | |||
| * `REGION_EU868` - Enables support for the Region EU868 (Default ON) | |||
| * `REGION_US915` - Enables support for the Region US915 (Default OFF) | |||
| * `REGION_CN779` - Enables support for the Region CN779 (Default OFF) | |||
| * `REGION_EU433` - Enables support for the Region EU433 (Default OFF) | |||
| * `REGION_AU915` - Enables support for the Region AU915 (Default OFF) | |||
| * `REGION_AS923` - Enables support for the Region AS923 (Default OFF) | |||
| * `REGION_CN470` - Enables support for the Region CN470 (Default OFF) | |||
| * `REGION_KR920` - Enables support for the Region IN865 (Default OFF) | |||
| * `REGION_IN865` - Enables support for the Region AS923 (Default OFF) | |||
| * `REGION_RU864` - Enables support for the Region RU864 (Default OFF) | |||
| ### Options that are automatically set | |||
| * `RADIO` - Defines the radio to be used. | |||
| The possible choices are: | |||
| * sx1272 | |||
| * sx1276 | |||
| * `LINKER_SCRIPT` - Defines the target specific linker script path. | |||
| * `OPENOCD_BIN` - Defines the OpenOCD path. | |||
| * `OPENOCD_INTERFACE` - Defines the interface configuration file to be used by OpenOCD. | |||
| * `OPENOCD_TARGET` - Defines the target configuration file to be used by OpenOCD. | |||
| # Debugging | |||
| 1. OpenOCD | |||
| OpenOCD has to be started with parameters that depend on the used debugger device and target board. | |||
| Some examples are shown below: | |||
| * NucleoL073 + STLinkV2-1 (On board debugger): | |||
| `openocd -f interface/stlink-v2-1.cfg -f target/stm32l0.cfg` | |||
| * SAMR34 Xplained Pro (On board debugger, tested with openocd 0.10, did not work with 0.9): | |||
| `openocd -f interface/cmsis-dap.cfg -f target/at91samdXX.cfg` | |||
| 2. GDB | |||
| The below GDB usage example shows how to start a debug session, writing the program to the flash and run. | |||
| * Run ARM-GNU GDB with: | |||
| `arm-none-eabi-gdb` | |||
| * Choose the program you want to debug: | |||
| `file src/apps/LoRaMac/LoRaMac-classA` | |||
| * Connect GDB to OpenOCD: | |||
| `target extended-remote localhost:3333` | |||
| * Execute a reset and halt of the target: | |||
| `monitor reset halt` | |||
| * Flash the program to the target Flash memory: | |||
| `load` | |||
| * Add a one-time break point at main: | |||
| `thbreak main` | |||
| * Run the program until the break point: | |||
| `continue` | |||
| * Finally run the program: | |||
| `continue` | |||
| # IDE Support | |||
| ## VSCode | |||
| ### Additional Prerequisites | |||
| * Visual Studio Code: | |||
| * GNU/Linux, Windows and OSX: | |||
| * [Download](https://code.visualstudio.com/Download) | |||
| * Extensions: Open `VSCode ->EXTENSION (Crtl+Shift+x)` and search for: | |||
| * C/C++ | |||
| * CMake | |||
| * CMake Tools | |||
| * Native Debug | |||
| ### Configuration | |||
| For Windows platforms it is necessary to make some additional configurations. Open your settings under *File->Preferences->Settings* and add the following lines: | |||
| Add MinGW Makefiles as preferred Generator: | |||
| ```json | |||
| "cmake.preferredGenerators": [ | |||
| "MinGW Makefiles", | |||
| "Ninja", | |||
| "Unix Makefiles" | |||
| ] | |||
| ``` | |||
| Set the CMake path: | |||
| ```json | |||
| "cmake.cmakePath": "path/to/cmake.exe" | |||
| ``` | |||
| ### Usage | |||
| 1. Open the directory of the cloned repository. | |||
| The *CMake Tools* extension will automatically generate a *`.cmaketools.json`* file based on the CMakeLists. | |||
| 2. The *`settings.json`* file under `.vscode` directory is the place where one can change the build options. | |||
| These are the build options that will be provided to CMake. | |||
| Please see chapter [Commandline Build Instructions](#commandline-build-instructions) for information about build options. | |||
| 3. Click on the blue status bar of *CMake Tools* to choose a build type (`Debug` or `Release`). | |||
| A CMake configuration process will be performed. | |||
| 4. A `Build` button will now be available. | |||
| Click this button to build the target. | |||
| 5. The CMake build system will automatically generate a *`launch.json`* file which setups the debugging process for the given board. | |||
| 6. Press the `F5` key to start a debug session. | |||
| This will automatically start the GDB and OpenOCD processes. | |||
| ### Useful Hints | |||
| * Change CMake options: Open the Command palette (Crtl+Shift+P) and type `CMake: Edit the CMake Cache` | |||
| * Execute a clean rebuild: Open the Command palette (Crtl+Shift+P) and type `CMake: Clean rebuild` | |||
| For detailed information about CMake Tools extension please see their [github repository](https://github.com/vector-of-bool/vscode-cmake-tools). | |||
| ## KDevelop | |||
| ### Additional Prerequisites | |||
| * KDevelop: | |||
| * GNU/Linux: | |||
| * Ubuntu 16.04/ Linux Mint 18: `apt-get install kdevelop` | |||
| * Linux Arch: `pacman -S kdevelop` | |||
| * Windows: | |||
| * [KDevelop Download](https://www.kdevelop.org/download) | |||
| **Note**: Currently there is no GDB support but it is planned for future releases. | |||
| * OSX: | |||
| * [KDevelop Download](https://www.kdevelop.org/download). | |||
| No official binaries are available. Must be built from source code. | |||
| ### Usage | |||
| 1. To open the project click on *`Project->Open /Import Project...`* and choose the top level `CMakeLists.txt` directory of the cloned repository. | |||
| Follow the indications to setup the project and add `-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-none-eabi.cmake` to the *`Extra Arguments`*. | |||
| 2. The CMake options and variables can be changed by right-clicking on project and selecting *`Open configuration...`*. | |||
| A graphical interface will pop-up. | |||
| Please see chapter [Commandline Build Instructions](#commandline-build-instructions) for information about build options. | |||
| 3. Click on `Build` to build the project. | |||
| 4. Create a launch configuration for debugging: | |||
| * Click on *`Run->Configure Launches...`* and add a new *`Compiled Binary Launcher`*. | |||
| * Set the field *`Debugger executable`* according to your system. For example `/usr/bin/arm-none-eabi-gdb` . | |||
| * Choose the `Run gdb script` according to the application you want to debug. | |||
| For example: `loramac-node/build/src/apps/LoRaMac/openocd-run.gdb`. | |||
| **Note**: The CMake build system will automatically generate the GDB run script. | |||
| 5. Start OpenOCD in a command line terminal as described on chapter [Debugging](#debugging). | |||
| 6. Click on "Debug" to launch a debug session. | |||
| @@ -0,0 +1,222 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(lora-mac) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Allow switching of target platform | |||
| set(BOARD_LIST NAMote72 NucleoL073 NucleoL152 NucleoL476 SAMR34 SKiM880B SKiM980A SKiM881AXL B-L072Z-LRWAN1) | |||
| set(BOARD NucleoL073 CACHE STRING "Default target platform is NucleoL073") | |||
| set_property(CACHE BOARD PROPERTY STRINGS ${BOARD_LIST}) | |||
| # Allow switching of MBED shields | |||
| set(MBED_RADIO_SHIELD_LIST SX1272MB2DAS SX1276MB1LAS SX1276MB1MAS SX1261MBXBAS SX1262MBXCAS SX1262MBXDAS ) | |||
| set(MBED_RADIO_SHIELD SX1261MBXBAS CACHE STRING "Default MBED radio shield is SX1261MBXBAS") | |||
| set_property(CACHE MBED_RADIO_SHIELD PROPERTY STRINGS ${MBED_RADIO_SHIELD_LIST}) | |||
| # Allow switching of secure-elements | |||
| set(SECURE_ELEMENT_LIST SOFT_SE LR1110_SE) | |||
| set(SECURE_ELEMENT SOFT_SE CACHE STRING "Default secure element is SOFT_SE") | |||
| set_property(CACHE SECURE_ELEMENT PROPERTY STRINGS ${SECURE_ELEMENT_LIST}) | |||
| # Allow switching of Applications | |||
| set(APPLICATION_LIST LoRaMac ping-pong rx-sensi tx-cw ) | |||
| set(APPLICATION LoRaMac CACHE STRING "Default Application is LoRaMac") | |||
| set_property(CACHE APPLICATION PROPERTY STRINGS ${APPLICATION_LIST}) | |||
| # Switch for USB-Uart support, enable it for some Applications who needs it. | |||
| option(USE_USB_CDC "Use USB-Uart" OFF) | |||
| # Switch for debugger support. | |||
| option(USE_DEBUGGER "Use Debugger" ON) | |||
| # Switch for Class B support of LoRaMac. | |||
| option(CLASSB_ENABLED "Class B support of LoRaMac" OFF) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Target Boards | |||
| #--------------------------------------------------------------------------------------- | |||
| if(BOARD STREQUAL NAMote72) | |||
| # Configure toolchain for NAMote72 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/NAMote72/cmsis/arm-gcc/stm32l152xc_flash.ld) | |||
| include(stm32l1) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/NAMote72) | |||
| # Configure radio | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(BOARD STREQUAL NucleoL073) | |||
| # Configure toolchain for NucleoL073 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL073/cmsis/arm-gcc/stm32l073xx_flash.ld) | |||
| include(stm32l0) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL073) | |||
| # Configure radio | |||
| if(MBED_RADIO_SHIELD STREQUAL SX1272MB2DAS) | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1276MB1LAS OR MBED_RADIO_SHIELD STREQUAL SX1276MB1MAS) | |||
| set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1261MBXBAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXCAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXDAS) | |||
| set(RADIO sx126x CACHE INTERNAL "Radio sx126x selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL LR1110MB1XXS) | |||
| set(RADIO lr1110 CACHE INTERNAL "Radio lr1110 selected") | |||
| else() | |||
| message(STATUS "Please specify the MBED_RADIO_SHIELD!\nPossible values are: SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS, SX1262MBXCAS, SX1262MBXDAS and LR1110MB1XXS.") | |||
| endif() | |||
| elseif(BOARD STREQUAL NucleoL152) | |||
| # Configure toolchain for NucleoL152 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL152/cmsis/arm-gcc/stm32l152xe_flash.ld) | |||
| include(stm32l1) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL152) | |||
| # Configure radio | |||
| if(MBED_RADIO_SHIELD STREQUAL SX1272MB2DAS) | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1276MB1LAS OR MBED_RADIO_SHIELD STREQUAL SX1276MB1MAS) | |||
| set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1261MBXBAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXCAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXDAS) | |||
| set(RADIO sx126x CACHE INTERNAL "Radio sx126x selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL LR1110MB1XXS) | |||
| set(RADIO lr1110 CACHE INTERNAL "Radio lr1110 selected") | |||
| else() | |||
| message(STATUS "Please specify the MBED_RADIO_SHIELD!\nPossible values are: SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS, SX1262MBXCAS, SX1262MBXDAS and LR1110MB1XXS.") | |||
| endif() | |||
| elseif(BOARD STREQUAL NucleoL476) | |||
| # Configure toolchain for NucleoL476 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL476/cmsis/arm-gcc/stm32l476rgtx_flash.ld) | |||
| include(stm32l4) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/NucleoL476) | |||
| # Configure radio | |||
| if(MBED_RADIO_SHIELD STREQUAL SX1272MB2DAS) | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1276MB1LAS OR MBED_RADIO_SHIELD STREQUAL SX1276MB1MAS) | |||
| set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL SX1261MBXBAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXCAS OR MBED_RADIO_SHIELD STREQUAL SX1262MBXDAS) | |||
| set(RADIO sx126x CACHE INTERNAL "Radio sx126x selected") | |||
| elseif(MBED_RADIO_SHIELD STREQUAL LR1110MB1XXS) | |||
| set(RADIO lr1110 CACHE INTERNAL "Radio lr1110 selected") | |||
| else() | |||
| message(STATUS "Please specify the MBED_RADIO_SHIELD!\nPossible values are: SX1272MB2DAS, SX1276MB1LAS, SX1276MB1MAS, SX1261MBXBAS, SX1262MBXCAS, SX1262MBXDAS and LR1110MB1XXS.") | |||
| endif() | |||
| elseif(BOARD STREQUAL SAMR34) | |||
| # Configure toolchain for SAMR34 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/mcu/saml21/saml21b/gcc/gcc/saml21j18b_flash.ld) | |||
| include(samr34) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/SAMR34) | |||
| # Configure radio | |||
| set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") | |||
| elseif(BOARD STREQUAL SKiM880B) | |||
| # Configure toolchain for SKiM881AXL | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM880B/cmsis/arm-gcc/stm32l151xba_flash.ld) | |||
| include(stm32l1) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM880B) | |||
| # Configure radio | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(BOARD STREQUAL SKiM980A) | |||
| # Configure toolchain for SKiM881AXL | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM980A/cmsis/arm-gcc/stm32l151xba_flash.ld) | |||
| include(stm32l1) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM980A) | |||
| # Configure radio | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(BOARD STREQUAL SKiM881AXL) | |||
| # Configure toolchain for SKiM881AXL | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM881AXL/cmsis/arm-gcc/stm32l081xx_flash.ld) | |||
| include(stm32l0) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM881AXL) | |||
| # Configure radio | |||
| set(RADIO sx1272 CACHE INTERNAL "Radio sx1272 selected") | |||
| elseif(BOARD STREQUAL B-L072Z-LRWAN1) | |||
| # Configure toolchain for B-L072Z-LRWAN1 | |||
| set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/B-L072Z-LRWAN1/cmsis/arm-gcc/stm32l072xx_flash.ld) | |||
| include(stm32l0) | |||
| # Build platform specific board implementation | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/B-L072Z-LRWAN1) | |||
| # Configure radio | |||
| set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") | |||
| endif() | |||
| #--------------------------------------------------------------------------------------- | |||
| # General Components | |||
| #--------------------------------------------------------------------------------------- | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/radio) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/system) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mac) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/peripherals) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Applications | |||
| #--------------------------------------------------------------------------------------- | |||
| if(APPLICATION STREQUAL LoRaMac) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/apps/LoRaMac) | |||
| elseif(APPLICATION STREQUAL ping-pong) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/apps/ping-pong) | |||
| elseif(APPLICATION STREQUAL rx-sensi) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/apps/rx-sensi) | |||
| elseif(APPLICATION STREQUAL tx-cw) | |||
| add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/apps/tx-cw) | |||
| endif() | |||
| @@ -0,0 +1,170 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(LoRaMac) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Allow switching of sub projects | |||
| set(SUB_PROJECT_LIST periodic-uplink-lpp fuota-test-01) | |||
| set(SUB_PROJECT periodic-uplink-lpp CACHE STRING "Default sub project is periodic-uplink-lpp") | |||
| set_property(CACHE SUB_PROJECT PROPERTY STRINGS ${SUB_PROJECT_LIST}) | |||
| # Allow switching of active region | |||
| set(ACTIVE_REGION_LIST LORAMAC_REGION_EU868 LORAMAC_REGION_US915 LORAMAC_REGION_CN779 | |||
| LORAMAC_REGION_EU433 LORAMAC_REGION_AU915 LORAMAC_REGION_AS923 LORAMAC_REGION_CN470 | |||
| LORAMAC_REGION_KR920 LORAMAC_REGION_IN865 LORAMAC_REGION_RU864 | |||
| ) | |||
| set(ACTIVE_REGION LORAMAC_REGION_EU868 CACHE STRING "Default active region is EU868") | |||
| set_property(CACHE ACTIVE_REGION PROPERTY STRINGS ${ACTIVE_REGION_LIST}) | |||
| if((SUB_PROJECT STREQUAL periodic-uplink-lpp OR SUB_PROJECT STREQUAL fuota-test-01) AND NOT CLASSB_ENABLED ) | |||
| message(FATAL_ERROR "Please turn on Class B support of LoRaMac ( CLASSB_ENABLED=ON ) to use periodic-uplink-lpp, fuota-test-01 sub projects") | |||
| endif() | |||
| # Allow selection of secure-element provisioning method | |||
| option(SECURE_ELEMENT_PRE_PROVISIONED "Secure-element pre-provisioning" ON) | |||
| if(SUB_PROJECT STREQUAL periodic-uplink-lpp) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Application common features handling | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_COMMON | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/CayenneLpp.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/cli.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandlerMsgDisplay.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/NvmDataMgmt.c" | |||
| ) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Application LoRaMac handler | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_LMH | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/LmHandler.c" | |||
| ) | |||
| #--------------------------------------------------------------------------------------- | |||
| # LoRaMac handler applicative packages | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_LMHP | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/FragDecoder.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpClockSync.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpCompliance.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpFragmentation.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpRemoteMcastSetup.c" | |||
| ) | |||
| elseif(SUB_PROJECT STREQUAL fuota-test-01) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Application common features handling | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_COMMON | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/cli.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandlerMsgDisplay.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/NvmDataMgmt.c" | |||
| ) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Application LoRaMac handler | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_LMH | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/LmHandler.c" | |||
| ) | |||
| #--------------------------------------------------------------------------------------- | |||
| # LoRaMac handler applicative packages | |||
| #--------------------------------------------------------------------------------------- | |||
| list(APPEND ${PROJECT_NAME}_LMHP | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/FragDecoder.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpClockSync.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpCompliance.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpFragmentation.c" | |||
| "${CMAKE_CURRENT_LIST_DIR}/common/LmHandler/packages/LmhpRemoteMcastSetup.c" | |||
| ) | |||
| else() | |||
| message(FATAL_ERROR "Unknown SUB_PROJECT") | |||
| endif() | |||
| #--------------------------------------------------------------------------------------- | |||
| # Application | |||
| #--------------------------------------------------------------------------------------- | |||
| file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/${SUB_PROJECT}/${BOARD}/*.c") | |||
| add_executable(${PROJECT_NAME}-${SUB_PROJECT} | |||
| ${${PROJECT_NAME}_COMMON} | |||
| ${${PROJECT_NAME}_LMH} | |||
| ${${PROJECT_NAME}_LMHP} | |||
| ${${PROJECT_NAME}_SOURCES} | |||
| $<TARGET_OBJECTS:mac> | |||
| $<TARGET_OBJECTS:system> | |||
| $<TARGET_OBJECTS:radio> | |||
| $<TARGET_OBJECTS:peripherals> | |||
| $<TARGET_OBJECTS:${BOARD}> | |||
| ) | |||
| target_compile_definitions(${PROJECT_NAME}-${SUB_PROJECT} PRIVATE $<$<BOOL:${CLASSB_ENABLED}>:LORAMAC_CLASSB_ENABLED>) | |||
| target_compile_definitions(${PROJECT_NAME}-${SUB_PROJECT} PRIVATE ACTIVE_REGION=${ACTIVE_REGION}) | |||
| if(${SECURE_ELEMENT_PRE_PROVISIONED} MATCHES ON) | |||
| target_compile_definitions(${PROJECT_NAME}-${SUB_PROJECT} PRIVATE -DSECURE_ELEMENT_PRE_PROVISIONED) | |||
| endif() | |||
| if(${SECURE_ELEMENT} MATCHES SOFT_SE) | |||
| target_compile_definitions(${PROJECT_NAME}-${SUB_PROJECT} PRIVATE -DSOFT_SE) | |||
| endif() | |||
| target_compile_definitions(${PROJECT_NAME}-${SUB_PROJECT} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:mac,INTERFACE_COMPILE_DEFINITIONS>> | |||
| ) | |||
| target_include_directories(${PROJECT_NAME}-${SUB_PROJECT} PUBLIC | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/common | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/common/LmHandler | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/common/LmHandler/packages | |||
| ${CMAKE_CURRENT_SOURCE_DIR}/${SUB_PROJECT}/${BOARD} | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:mac,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:system,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:radio,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:peripherals,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:${BOARD},INTERFACE_INCLUDE_DIRECTORIES>> | |||
| ) | |||
| set_property(TARGET ${PROJECT_NAME}-${SUB_PROJECT} PROPERTY C_STANDARD 11) | |||
| target_link_libraries(${PROJECT_NAME}-${SUB_PROJECT} m) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Debugging and Binutils | |||
| #--------------------------------------------------------------------------------------- | |||
| include(gdb-helper) | |||
| include(binutils-arm-none-eabi) | |||
| # Generate debugger configurations | |||
| generate_run_gdb_stlink(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| generate_run_gdb_openocd(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| generate_vscode_launch_openocd(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| # Print section sizes of target | |||
| print_section_sizes(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| # Create output in hex and binary format | |||
| create_bin_output(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| create_hex_output(${PROJECT_NAME}-${SUB_PROJECT}) | |||
| @@ -0,0 +1,257 @@ | |||
| /*! | |||
| * \file CayenneLpp.c | |||
| * | |||
| * \brief Implements the Cayenne Low Power Protocol | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include <stdint.h> | |||
| #include "utilities.h" | |||
| #include "CayenneLpp.h" | |||
| #define CAYENNE_LPP_MAXBUFFER_SIZE 242 | |||
| static uint8_t CayenneLppBuffer[CAYENNE_LPP_MAXBUFFER_SIZE]; | |||
| static uint8_t CayenneLppCursor = 0; | |||
| void CayenneLppInit( void ) | |||
| { | |||
| CayenneLppCursor = 0; | |||
| } | |||
| void CayenneLppReset( void ) | |||
| { | |||
| CayenneLppCursor = 0; | |||
| } | |||
| uint8_t CayenneLppGetSize( void ) | |||
| { | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t* CayenneLppGetBuffer( void ) | |||
| { | |||
| return CayenneLppBuffer; | |||
| } | |||
| uint8_t CayenneLppCopy( uint8_t* dst ) | |||
| { | |||
| memcpy1( dst, CayenneLppBuffer, CayenneLppCursor ); | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_DIGITAL_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_INPUT; | |||
| CayenneLppBuffer[CayenneLppCursor++] = value; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_DIGITAL_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_OUTPUT; | |||
| CayenneLppBuffer[CayenneLppCursor++] = value; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_ANALOG_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t val = ( int16_t ) ( value * 100 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_INPUT; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_ANALOG_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t val = ( int16_t ) ( value * 100 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_OUTPUT; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_LUMINOSITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_LUMINOSITY; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lux >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lux; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_PRESENCE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_PRESENCE; | |||
| CayenneLppBuffer[CayenneLppCursor++] = value; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_TEMPERATURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t val = ( int16_t) ( celsius * 10 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_TEMPERATURE; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_RELATIVE_HUMIDITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_RELATIVE_HUMIDITY; | |||
| CayenneLppBuffer[CayenneLppCursor++] = (uint8_t ) ( rh * 2 ); | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_ACCELEROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t vx = ( int16_t ) ( x * 1000 ); | |||
| int16_t vy = ( int16_t ) ( y * 1000 ); | |||
| int16_t vz = ( int16_t ) ( z * 1000 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_ACCELEROMETER; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vx >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vx; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vy >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vy; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vz >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vz; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_BAROMETRIC_PRESSURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t val = ( int16_t ) ( hpa * 10 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_BAROMETRIC_PRESSURE; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = val; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_GYROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int16_t vx = ( int16_t ) ( x * 100 ); | |||
| int16_t vy = ( int16_t ) ( y * 100 ); | |||
| int16_t vz = ( int16_t ) ( z * 100 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_GYROMETER; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vx >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vx; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vy >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vy; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vz >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = vz; | |||
| return CayenneLppCursor; | |||
| } | |||
| uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters ) | |||
| { | |||
| if( ( CayenneLppCursor + LPP_GPS_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) | |||
| { | |||
| return 0; | |||
| } | |||
| int32_t lat = ( int32_t ) ( latitude * 10000 ); | |||
| int32_t lon = ( int32_t ) ( longitude * 10000 ); | |||
| int32_t alt = ( int32_t ) ( meters * 100 ); | |||
| CayenneLppBuffer[CayenneLppCursor++] = channel; | |||
| CayenneLppBuffer[CayenneLppCursor++] = LPP_GPS; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lat >> 16; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lat >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lat; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lon >> 16; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lon >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = lon; | |||
| CayenneLppBuffer[CayenneLppCursor++] = alt >> 16; | |||
| CayenneLppBuffer[CayenneLppCursor++] = alt >> 8; | |||
| CayenneLppBuffer[CayenneLppCursor++] = alt; | |||
| return CayenneLppCursor; | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| /*! | |||
| * \file CayenneLpp.h | |||
| * | |||
| * \brief Implements the Cayenne Low Power Protocol | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __CAYENNE_LPP_H__ | |||
| #define __CAYENNE_LPP_H__ | |||
| #include <stdint.h> | |||
| #define LPP_DIGITAL_INPUT 0 // 1 byte | |||
| #define LPP_DIGITAL_OUTPUT 1 // 1 byte | |||
| #define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed | |||
| #define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed | |||
| #define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned | |||
| #define LPP_PRESENCE 102 // 1 byte, 1 | |||
| #define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed | |||
| #define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned | |||
| #define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G | |||
| #define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned | |||
| #define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s | |||
| #define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m | |||
| // Data ID + Data Type + Data Size | |||
| #define LPP_DIGITAL_INPUT_SIZE 3 | |||
| #define LPP_DIGITAL_OUTPUT_SIZE 3 | |||
| #define LPP_ANALOG_INPUT_SIZE 4 | |||
| #define LPP_ANALOG_OUTPUT_SIZE 4 | |||
| #define LPP_LUMINOSITY_SIZE 4 | |||
| #define LPP_PRESENCE_SIZE 3 | |||
| #define LPP_TEMPERATURE_SIZE 4 | |||
| #define LPP_RELATIVE_HUMIDITY_SIZE 3 | |||
| #define LPP_ACCELEROMETER_SIZE 8 | |||
| #define LPP_BAROMETRIC_PRESSURE_SIZE 4 | |||
| #define LPP_GYROMETER_SIZE 8 | |||
| #define LPP_GPS_SIZE 11 | |||
| void CayenneLppInit( void ); | |||
| void CayenneLppReset( void ); | |||
| uint8_t CayenneLppGetSize( void ); | |||
| uint8_t* CayenneLppGetBuffer( void ); | |||
| uint8_t CayenneLppCopy( uint8_t* buffer ); | |||
| uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value ); | |||
| uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value ); | |||
| uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value ); | |||
| uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value ); | |||
| uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux ); | |||
| uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value ); | |||
| uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius ); | |||
| uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh ); | |||
| uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z ); | |||
| uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa ); | |||
| uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z ); | |||
| uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters ); | |||
| #endif // __CAYENNE_LPP_H__ | |||
| @@ -0,0 +1,63 @@ | |||
| /*! | |||
| * \file Commissioning.h | |||
| * | |||
| * \brief End-device commissioning parameters | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #ifndef __COMMISSIONING_H__ | |||
| #define __COMMISSIONING_H__ | |||
| /*! | |||
| ****************************************************************************** | |||
| ********************************** WARNING *********************************** | |||
| ****************************************************************************** | |||
| The LoRaWAN AES128 keys are stored and provisionned on secure-elements. | |||
| This project providdes a software emulated secure-element. | |||
| The LoRaWAN AES128 keys SHALL be updated under | |||
| src/peripherals/<secure-element name>-se\se-identity.h file. | |||
| ****************************************************************************** | |||
| ****************************************************************************** | |||
| ****************************************************************************** | |||
| */ | |||
| #include "se-identity.h" | |||
| /*! | |||
| * When set to 1 the application uses the Over-the-Air activation procedure | |||
| * When set to 0 the application uses the Personalization activation procedure | |||
| */ | |||
| #define OVER_THE_AIR_ACTIVATION 1 | |||
| /*! | |||
| * When using ABP activation the MAC layer must know in advance to which server | |||
| * version it will be connected. | |||
| */ | |||
| #define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000400 // 1.0.4.0 | |||
| #define ABP_ACTIVATION_LRWAN_VERSION ABP_ACTIVATION_LRWAN_VERSION_V10x | |||
| /*! | |||
| * Indicates if the end-device is to be connected to a private or public network | |||
| */ | |||
| #define LORAWAN_PUBLIC_NETWORK true | |||
| /*! | |||
| * Current network ID | |||
| */ | |||
| #define LORAWAN_NETWORK_ID ( uint32_t )0 | |||
| #endif // __COMMISSIONING_H__ | |||
| @@ -0,0 +1,349 @@ | |||
| /*! | |||
| * \file LmHandler.h | |||
| * | |||
| * \brief Implements the LoRaMac layer handling. | |||
| * Provides the possibility to register applicative packages. | |||
| * | |||
| * \remark Inspired by the examples provided on the en.i-cube_lrwan fork. | |||
| * MCD Application Team ( STMicroelectronics International ) | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LORAMAC_HANDLER_H__ | |||
| #define __LORAMAC_HANDLER_H__ | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| #include "LmHandlerTypes.h" | |||
| typedef struct LmHandlerJoinParams_s | |||
| { | |||
| CommissioningParams_t *CommissioningParams; | |||
| int8_t Datarate; | |||
| LmHandlerErrorStatus_t Status; | |||
| }LmHandlerJoinParams_t; | |||
| typedef struct LmHandlerTxParams_s | |||
| { | |||
| uint8_t IsMcpsConfirm; | |||
| LoRaMacEventInfoStatus_t Status; | |||
| CommissioningParams_t *CommissioningParams; | |||
| LmHandlerMsgTypes_t MsgType; | |||
| uint8_t AckReceived; | |||
| int8_t Datarate; | |||
| uint32_t UplinkCounter; | |||
| LmHandlerAppData_t AppData; | |||
| int8_t TxPower; | |||
| uint8_t Channel; | |||
| }LmHandlerTxParams_t; | |||
| typedef struct LmHandlerRxParams_s | |||
| { | |||
| uint8_t IsMcpsIndication; | |||
| LoRaMacEventInfoStatus_t Status; | |||
| CommissioningParams_t *CommissioningParams; | |||
| int8_t Datarate; | |||
| int8_t Rssi; | |||
| int8_t Snr; | |||
| uint32_t DownlinkCounter; | |||
| int8_t RxSlot; | |||
| }LmHandlerRxParams_t; | |||
| typedef struct LoRaMacHandlerBeaconParams_s | |||
| { | |||
| LoRaMacEventInfoStatus_t Status; | |||
| LmHandlerBeaconState_t State; | |||
| BeaconInfo_t Info; | |||
| }LoRaMacHandlerBeaconParams_t; | |||
| typedef struct LmHandlerParams_s | |||
| { | |||
| /*! | |||
| * Region | |||
| */ | |||
| LoRaMacRegion_t Region; | |||
| /*! | |||
| * Holds the ADR state | |||
| */ | |||
| bool AdrEnable; | |||
| /*! | |||
| * Uplink frame type | |||
| */ | |||
| LmHandlerMsgTypes_t IsTxConfirmed; | |||
| /*! | |||
| * Uplink datarate, when \ref AdrEnable is OFF | |||
| */ | |||
| int8_t TxDatarate; | |||
| /*! | |||
| * Enables/Disables a public network usage | |||
| */ | |||
| bool PublicNetworkEnable; | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| bool DutyCycleEnabled; | |||
| /*! | |||
| * Application data buffer maximum size | |||
| */ | |||
| uint8_t DataBufferMaxSize; | |||
| /*! | |||
| * Application data buffer pointer | |||
| */ | |||
| uint8_t *DataBuffer; | |||
| /*! | |||
| * Class B ping-slot periodicity. | |||
| */ | |||
| bool PingSlotPeriodicity; | |||
| }LmHandlerParams_t; | |||
| typedef struct LmHandlerCallbacks_s | |||
| { | |||
| /*! | |||
| * Get the current battery level | |||
| * | |||
| * \retval value Battery level ( 0: very low, 254: fully charged ) | |||
| */ | |||
| uint8_t ( *GetBatteryLevel )( void ); | |||
| /*! | |||
| * Get the current temperature | |||
| * | |||
| * \retval value Temperature in degree Celsius | |||
| */ | |||
| float ( *GetTemperature )( void ); | |||
| /*! | |||
| * Returns a pseudo random seed generated using the MCU Unique ID | |||
| * | |||
| * \retval seed Generated pseudo random seed | |||
| */ | |||
| uint32_t ( *GetRandomSeed )( void ); | |||
| /*! | |||
| *\brief Will be called each time a Radio IRQ is handled by the MAC | |||
| * layer. | |||
| * | |||
| *\warning Runs in a IRQ context. Should only change variables state. | |||
| */ | |||
| void ( *OnMacProcess )( void ); | |||
| /*! | |||
| * Notifies the upper layer that the NVM context has changed | |||
| * | |||
| * \param [IN] state Indicates if we are storing (true) or | |||
| * restoring (false) the NVM context | |||
| * | |||
| * \param [IN] size Number of data bytes which were stored or restored. | |||
| */ | |||
| void ( *OnNvmDataChange )( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| /*! | |||
| * Notifies the upper layer that a network parameters have been set | |||
| * | |||
| * \param [IN] params notification parameters | |||
| */ | |||
| void ( *OnNetworkParametersChange )( CommissioningParams_t *params ); | |||
| /*! | |||
| * Notifies the upper layer that a MCPS request has been made to the MAC layer | |||
| * | |||
| * \param [IN] status - Request returned status | |||
| * \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t. | |||
| * \param [IN] nextTxDelay - Time to wait until another TX is possible. | |||
| */ | |||
| void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay ); | |||
| /*! | |||
| * Notifies the upper layer that a MLME request has been made to the MAC layer | |||
| * | |||
| * \param [IN] status - Request returned status | |||
| * \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t. | |||
| * \param [IN] nextTxDelay - Time to wait until another TX is possible. | |||
| */ | |||
| void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay ); | |||
| /*! | |||
| * Notifies the upper layer that a network has been joined | |||
| * | |||
| * \param [IN] params notification parameters | |||
| */ | |||
| void ( *OnJoinRequest )( LmHandlerJoinParams_t *params ); | |||
| /*! | |||
| * Notifies upper layer that a frame has been transmitted | |||
| * | |||
| * \param [IN] params notification parameters | |||
| */ | |||
| void ( *OnTxData )( LmHandlerTxParams_t *params ); | |||
| /*! | |||
| * Notifies the upper layer that an applicative frame has been received | |||
| * | |||
| * \param [IN] appData Received applicative data | |||
| * \param [IN] params notification parameters | |||
| */ | |||
| void ( *OnRxData )( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params ); | |||
| /*! | |||
| * Confirms the LoRaWAN device class change | |||
| * | |||
| * \param [IN] deviceClass New end-device class | |||
| */ | |||
| void ( *OnClassChange )( DeviceClass_t deviceClass ); | |||
| /*! | |||
| * Notifies the upper layer that the beacon status has changed | |||
| * | |||
| * \param [IN] params notification parameters | |||
| */ | |||
| void ( *OnBeaconStatusChange )( LoRaMacHandlerBeaconParams_t *params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| /*! | |||
| * Notifies the upper layer that the system time has been updated. | |||
| * | |||
| * \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second | |||
| * \param [in] timeCorrection Received time correction value | |||
| */ | |||
| void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| /*! | |||
| * Notifies the upper layer that the system time has been updated. | |||
| */ | |||
| void ( *OnSysTimeUpdate )( void ); | |||
| #endif | |||
| }LmHandlerCallbacks_t; | |||
| /*! | |||
| * LoRaMac handler initialisation | |||
| * | |||
| * \param [IN] callbacks LoRaMac handler callbacks | |||
| * \param [IN] handlerParams LoRaMac handler parameters | |||
| * | |||
| * \retval none | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *callbacks, | |||
| LmHandlerParams_t *handlerParams ); | |||
| /*! | |||
| * Indicates if the LoRaMacHandler is busy | |||
| * | |||
| * \retval status [true] Busy, [false] free | |||
| */ | |||
| bool LmHandlerIsBusy( void ); | |||
| /*! | |||
| * Processes the LoRaMac and Radio events. | |||
| * When no pendig operation asks to go in low power mode. | |||
| * | |||
| * \remark This function must be called in the main loop. | |||
| */ | |||
| void LmHandlerProcess( void ); | |||
| /*! | |||
| * Gets current duty-cycle wait time | |||
| * | |||
| * \retval time to wait in ms | |||
| */ | |||
| TimerTime_t LmHandlerGetDutyCycleWaitTime( void ); | |||
| /*! | |||
| * Instructs the MAC layer to send a ClassA uplink | |||
| * | |||
| * \param [IN] appData Data to be sent | |||
| * \param [IN] isTxConfirmed Indicates if the uplink requires an acknowledgement | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been | |||
| * processed else \ref LORAMAC_HANDLER_ERROR | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed ); | |||
| /*! | |||
| * Join a LoRa Network in classA | |||
| * | |||
| * \Note if the device is ABP, this is a pass through function | |||
| */ | |||
| void LmHandlerJoin( void ); | |||
| /*! | |||
| * Check whether the Device is joined to the network | |||
| * | |||
| * \param [IN] none | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET | |||
| */ | |||
| LmHandlerFlagStatus_t LmHandlerJoinStatus( void ); | |||
| /*! | |||
| * Informs the server on the ping-slot periodicity to use | |||
| * | |||
| * \param [IN] periodicity Is equal to 2^periodicity seconds. | |||
| * Example: 2^3 = 8 seconds. The end-device will open an Rx slot every 8 seconds. | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been | |||
| * processed else \ref LORAMAC_HANDLER_ERROR | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity ); | |||
| /*! | |||
| * Request the MAC layer to change LoRaWAN class | |||
| * | |||
| * \Note Callback \ref LmHandlerConfirmClass informs upper layer that the change has occurred | |||
| * \Note Only switch from class A to class B/C OR from class B/C to class A is allowed | |||
| * | |||
| * \param [IN] newClass New class to be requested | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been | |||
| * processed else \ref LORAMAC_HANDLER_ERROR | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass ); | |||
| /*! | |||
| * Gets the current LoRaWAN class | |||
| * | |||
| * \retval currentClass Current LoRaWAN class | |||
| */ | |||
| DeviceClass_t LmHandlerGetCurrentClass( void ); | |||
| /*! | |||
| * Gets the current datarate | |||
| * | |||
| * \retval currentDatarate Current datarate | |||
| */ | |||
| int8_t LmHandlerGetCurrentDatarate( void ); | |||
| /*! | |||
| * Gets the current active region | |||
| * | |||
| * \retval currentRegion Current active region | |||
| */ | |||
| LoRaMacRegion_t LmHandlerGetActiveRegion( void ); | |||
| /*! | |||
| * Set system maximum tolerated rx error in milliseconds | |||
| * | |||
| * \param [IN] maxErrorInMs Maximum tolerated error in milliseconds | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been | |||
| * processed else \ref LORAMAC_HANDLER_ERROR | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs ); | |||
| /* | |||
| *============================================================================= | |||
| * PACKAGES HANDLING | |||
| *============================================================================= | |||
| */ | |||
| LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params ); | |||
| bool LmHandlerPackageIsInitialized( uint8_t id ); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // __LORAMAC_HANDLER_H__ | |||
| @@ -0,0 +1,124 @@ | |||
| /*! | |||
| * \file LmHandlerTypes.h | |||
| * | |||
| * \brief Defines the types used by LmHandler | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LORAMAC_HANDLER_TYPES_H__ | |||
| #define __LORAMAC_HANDLER_TYPES_H__ | |||
| #include "LoRaMac.h" | |||
| /*! | |||
| * If set to 1 the new API defining \ref OnSysTimeUpdate callback is used. | |||
| */ | |||
| #define LMH_SYS_TIME_UPDATE_NEW_API 1 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_ADR_OFF = 0, | |||
| LORAMAC_HANDLER_ADR_ON = !LORAMAC_HANDLER_ADR_OFF | |||
| }LmHandlerAdrStates_t; | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_RESET = 0, | |||
| LORAMAC_HANDLER_SET = !LORAMAC_HANDLER_RESET | |||
| }LmHandlerFlagStatus_t; | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_ERROR = -1, | |||
| LORAMAC_HANDLER_SUCCESS = 0 | |||
| }LmHandlerErrorStatus_t; | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_UNCONFIRMED_MSG = 0, | |||
| LORAMAC_HANDLER_CONFIRMED_MSG = !LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| }LmHandlerMsgTypes_t; | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_FALSE = 0, | |||
| LORAMAC_HANDLER_TRUE = !LORAMAC_HANDLER_FALSE | |||
| }LmHandlerBoolean_t; | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_BEACON_ACQUIRING, | |||
| LORAMAC_HANDLER_BEACON_LOST, | |||
| LORAMAC_HANDLER_BEACON_RX, | |||
| LORAMAC_HANDLER_BEACON_NRX | |||
| }LmHandlerBeaconState_t; | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_NVM_RESTORE, | |||
| LORAMAC_HANDLER_NVM_STORE, | |||
| }LmHandlerNvmContextStates_t; | |||
| /*! | |||
| * Commissioning parameters | |||
| */ | |||
| typedef struct CommissioningParams_s | |||
| { | |||
| bool IsOtaaActivation; | |||
| uint8_t DevEui[8]; | |||
| uint8_t JoinEui[8]; | |||
| uint8_t SePin[4]; | |||
| uint32_t NetworkId; | |||
| uint32_t DevAddr; | |||
| }CommissioningParams_t; | |||
| /*! | |||
| * Application data structure | |||
| */ | |||
| typedef struct LmHandlerAppData_s | |||
| { | |||
| uint8_t Port; | |||
| uint8_t BufferSize; | |||
| uint8_t *Buffer; | |||
| }LmHandlerAppData_t; | |||
| typedef struct LmHandlerRequestParams_s | |||
| { | |||
| uint8_t IsMcpsRequest; | |||
| LoRaMacStatus_t Status; | |||
| union | |||
| { | |||
| Mcps_t Mcps; | |||
| Mlme_t Mlme; | |||
| }RequestType; | |||
| }LmHandlerRequestParams_t; | |||
| #endif // __LORAMAC_HANDLER_TYPES_H__ | |||
| @@ -0,0 +1,751 @@ | |||
| /*! | |||
| * \file FragDecoder.c | |||
| * | |||
| * \brief Implements the LoRa-Alliance fragmentation decoder | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Fabien Holin ( Semtech ) | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include <stddef.h> | |||
| #include <stdbool.h> | |||
| #include "utilities.h" | |||
| #include "FragDecoder.h" | |||
| #define DBG_TRACE 0 | |||
| #if DBG_TRACE == 1 | |||
| #include <stdio.h> | |||
| /*! | |||
| * Works in the same way as the printf function does. | |||
| */ | |||
| #define DBG( ... ) \ | |||
| do \ | |||
| { \ | |||
| printf( __VA_ARGS__ ); \ | |||
| }while( 0 ) | |||
| #else | |||
| #define DBG( fmt, ... ) | |||
| #endif | |||
| /* | |||
| *============================================================================= | |||
| * Fragmentation decoder algorithm utilities | |||
| *============================================================================= | |||
| */ | |||
| typedef struct | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| FragDecoderCallbacks_t *Callbacks; | |||
| #else | |||
| uint8_t *File; | |||
| uint32_t FileSize; | |||
| #endif | |||
| uint16_t FragNb; | |||
| uint8_t FragSize; | |||
| uint32_t M2BLine; | |||
| uint8_t MatrixM2B[( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY]; | |||
| uint16_t FragNbMissingIndex[FRAG_MAX_NB]; | |||
| uint8_t S[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; | |||
| FragDecoderStatus_t Status; | |||
| }FragDecoder_t; | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * \brief Sets a row from source into file destination | |||
| * | |||
| * \param [IN] src Source buffer pointer | |||
| * \param [IN] row Destination index of the row to be copied | |||
| * \param [IN] size Source number of bytes to be copied | |||
| */ | |||
| static void SetRow( uint8_t *src, uint16_t row, uint16_t size ); | |||
| #else | |||
| /*! | |||
| * \brief Sets a row from source into destination | |||
| * | |||
| * \param [IN] dst Destination buffer pointer | |||
| * \param [IN] src Source buffer pointer | |||
| * \param [IN] row Destination index of the row to be copied | |||
| * \param [IN] size Source number of bytes to be copied | |||
| */ | |||
| static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * \brief Gets a row from source and stores it into file destination | |||
| * | |||
| * \param [IN] src Source buffer pointer | |||
| * \param [IN] row Source index of the row to be copied | |||
| * \param [IN] size Source number of bytes to be copied | |||
| */ | |||
| static void GetRow( uint8_t *src, uint16_t row, uint16_t size ); | |||
| #else | |||
| /*! | |||
| * \brief Gets a row from source and stores it into destination | |||
| * | |||
| * \param [IN] dst Destination buffer pointer | |||
| * \param [IN] src Source buffer pointer | |||
| * \param [IN] row Source index of the row to be copied | |||
| * \param [IN] size Source number of bytes to be copied | |||
| */ | |||
| static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ); | |||
| #endif | |||
| /*! | |||
| * \brief Gets the parity value from a given row of the parity matrix | |||
| * | |||
| * \param [IN] index The index of the row to be computed | |||
| * \param [IN] matrixRow Pointer to the parity matrix (parity bit array) | |||
| * | |||
| * \retval parity Parity value at the given index | |||
| */ | |||
| static uint8_t GetParity( uint16_t index, uint8_t *matrixRow ); | |||
| /*! | |||
| * \brief Sets the parity value on the given row of the parity matrix | |||
| * | |||
| * \param [IN] index The index of the row to be computed | |||
| * \param [IN/OUT] matrixRow Pointer to the parity matrix. | |||
| * \param [IN] parity The parity value to be set in the parity matrix | |||
| */ | |||
| static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity ); | |||
| /*! | |||
| * \brief Check if the provided value is a power of 2 | |||
| * | |||
| * \param [IN] x Value to be tested | |||
| * | |||
| * \retval status Return true if frame is a power of two | |||
| */ | |||
| static bool IsPowerOfTwo( uint32_t x ); | |||
| /*! | |||
| * \brief XOrs two data lines | |||
| * | |||
| * \param [IN] line1 1st Data line to be XORed | |||
| * \param [IN] line2 2nd Data line to be XORed | |||
| * \param [IN] size Number of elements in line1 | |||
| * | |||
| * \param [OUT] result XOR( line1, line2 ) result stored in line1 | |||
| */ | |||
| static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size ); | |||
| /*! | |||
| * \brief XORs two parity lines | |||
| * | |||
| * \param [IN] line1 1st Parity line to be XORed | |||
| * \param [IN] line2 2nd Parity line to be XORed | |||
| * \param [IN] size Number of elements in line1 | |||
| * | |||
| * \param [OUT] result XOR( line1, line2 ) result stored in line1 | |||
| */ | |||
| static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size ); | |||
| /*! | |||
| * \brief Generates a pseudo random number : PRBS23 | |||
| * | |||
| * \param [IN] value The input of the PRBS23 generator | |||
| * | |||
| * \retval nextValue Returns the next pseudo random number | |||
| */ | |||
| static int32_t FragPrbs23( int32_t value ); | |||
| /*! | |||
| * \brief Gets and fills the parity matrix | |||
| * | |||
| * \param [IN] n Fragment N | |||
| * \param [IN] m Fragment number | |||
| * \param [OUT] matrixRow Parity matrix | |||
| */ | |||
| static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow ); | |||
| /*! | |||
| * \brief Finds the index of the first one in a bit array | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] size Bit array size | |||
| * \retval index The index of the first 1 in the bit array | |||
| */ | |||
| static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size ); | |||
| /*! | |||
| * \brief Checks if the provided bit array only contains zeros | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] size Bit array size | |||
| * \retval isAllZeros [0: Contains ones, 1: Contains all zeros] | |||
| */ | |||
| static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size ); | |||
| /*! | |||
| * \brief Finds & marks missing fragments | |||
| * | |||
| * \param [IN] counter Current fragment counter | |||
| * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place | |||
| */ | |||
| static void FragFindMissingFrags( uint16_t counter ); | |||
| /*! | |||
| * \brief Finds the index (frag counter) of the x th missing frag | |||
| * | |||
| * \param [IN] x x th missing frag | |||
| * | |||
| * \retval counter The counter value associated to the x th missing frag | |||
| */ | |||
| static uint16_t FragFindMissingIndex( uint16_t x ); | |||
| /*! | |||
| * \brief Extacts a row from the binary matrix and expands it to a bitArray | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] rowIndex Matrix row index | |||
| * \param [IN] bitsInRow Number of bits in one row | |||
| */ | |||
| static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow ); | |||
| /*! | |||
| * \brief Collapses and Pushs a row of a bit array to the matrix | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] rowIndex Matrix row index | |||
| * \param [IN] bitsInRow Number of bits in one row | |||
| */ | |||
| static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow ); | |||
| /* | |||
| *============================================================================= | |||
| * Fragmentation decoder algorithm | |||
| *============================================================================= | |||
| */ | |||
| static FragDecoder_t FragDecoder; | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks ) | |||
| #else | |||
| void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize ) | |||
| #endif | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| FragDecoder.Callbacks = callbacks; | |||
| #else | |||
| FragDecoder.File = file; | |||
| FragDecoder.FileSize = fileSize; | |||
| #endif | |||
| FragDecoder.FragNb = fragNb; // FragNb = FRAG_MAX_SIZE | |||
| FragDecoder.FragSize = fragSize; // number of byte on a row | |||
| FragDecoder.Status.FragNbLastRx = 0; | |||
| FragDecoder.Status.FragNbLost = 0; | |||
| FragDecoder.M2BLine = 0; | |||
| // Initialize missing fragments index array | |||
| for( uint16_t i = 0; i < FRAG_MAX_NB; i++ ) | |||
| { | |||
| FragDecoder.FragNbMissingIndex[i] = 1; | |||
| } | |||
| // Initialize parity matrix | |||
| for( uint32_t i = 0; i < ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); i++ ) | |||
| { | |||
| FragDecoder.S[i] = 0; | |||
| } | |||
| for( uint32_t i = 0; i < ( ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY ); i++ ) | |||
| { | |||
| FragDecoder.MatrixM2B[i] = 0xFF; | |||
| } | |||
| // Initialize final uncoded data buffer ( FRAG_MAX_NB * FRAG_MAX_SIZE ) | |||
| for( uint32_t i = 0; i < ( fragNb * fragSize ); i++ ) | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) ) | |||
| { | |||
| uint8_t buffer[1] = { 0xFF }; | |||
| FragDecoder.Callbacks->FragDecoderWrite( i, buffer, 1 ); | |||
| } | |||
| #else | |||
| FragDecoder.File[i] = 0xFF; | |||
| #endif | |||
| } | |||
| FragDecoder.Status.FragNbLost = 0; | |||
| FragDecoder.Status.FragNbLastRx = 0; | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| uint32_t FragDecoderGetMaxFileSize( void ) | |||
| { | |||
| return FRAG_MAX_NB * FRAG_MAX_SIZE; | |||
| } | |||
| #endif | |||
| int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData ) | |||
| { | |||
| uint16_t firstOneInRow = 0; | |||
| int32_t first = 0; | |||
| int32_t noInfo = 0; | |||
| uint8_t matrixRow[(FRAG_MAX_NB >> 3 ) + 1]; | |||
| uint8_t matrixDataTemp[FRAG_MAX_SIZE]; | |||
| uint8_t dataTempVector[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; | |||
| uint8_t dataTempVector2[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; | |||
| memset1( matrixRow, 0, ( FRAG_MAX_NB >> 3 ) + 1 ); | |||
| memset1( matrixDataTemp, 0, FRAG_MAX_SIZE ); | |||
| memset1( dataTempVector, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); | |||
| memset1( dataTempVector2, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); | |||
| FragDecoder.Status.FragNbRx = fragCounter; | |||
| if( fragCounter < FragDecoder.Status.FragNbLastRx ) | |||
| { | |||
| return FRAG_SESSION_ONGOING; // Drop frame out of order | |||
| } | |||
| // The M (FragNb) first packets aren't encoded or in other words they are | |||
| // encoded with the unitary matrix | |||
| if( fragCounter < ( FragDecoder.FragNb + 1 ) ) | |||
| { | |||
| // The M first frame are not encoded store them | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| SetRow( rawData, fragCounter - 1, FragDecoder.FragSize ); | |||
| #else | |||
| SetRow( FragDecoder.File, rawData, fragCounter - 1, FragDecoder.FragSize ); | |||
| #endif | |||
| FragDecoder.FragNbMissingIndex[fragCounter - 1] = 0; | |||
| // Update the FragDecoder.FragNbMissingIndex with the loosing frame | |||
| FragFindMissingFrags( fragCounter ); | |||
| } | |||
| else | |||
| { | |||
| if( FragDecoder.Status.FragNbLost > FRAG_MAX_REDUNDANCY ) | |||
| { | |||
| FragDecoder.Status.MatrixError = 1; | |||
| return FRAG_SESSION_FINISHED; | |||
| } | |||
| // At this point we receive encoded frames and the number of loosing frames | |||
| // is well known: FragDecoder.FragNbLost - 1; | |||
| // In case of the end of true data is missing | |||
| FragFindMissingFrags( fragCounter ); | |||
| if( FragDecoder.Status.FragNbLost == 0 ) | |||
| { | |||
| // the case : all the M(FragNb) first rows have been transmitted with no error | |||
| return FragDecoder.Status.FragNbLost; | |||
| } | |||
| // fragCounter - FragDecoder.FragNb | |||
| FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow ); | |||
| for( int32_t i = 0; i < FragDecoder.FragNb; i++ ) | |||
| { | |||
| if( GetParity( i , matrixRow ) == 1 ) | |||
| { | |||
| if( FragDecoder.FragNbMissingIndex[i] == 0 ) | |||
| { | |||
| // XOR with already receive frag | |||
| SetParity( i, matrixRow, 0 ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| GetRow( matrixDataTemp, i, FragDecoder.FragSize ); | |||
| #else | |||
| GetRow( matrixDataTemp, FragDecoder.File, i, FragDecoder.FragSize ); | |||
| #endif | |||
| XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize ); | |||
| } | |||
| else | |||
| { | |||
| // Fill the "little" boolean matrix m2b | |||
| SetParity( FragDecoder.FragNbMissingIndex[i] - 1, dataTempVector, 1 ); | |||
| if( first == 0 ) | |||
| { | |||
| first = 1; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost ); | |||
| if( first > 0 ) | |||
| { | |||
| int32_t li; | |||
| int32_t lj; | |||
| // Manage a new line in MatrixM2B | |||
| while( GetParity( firstOneInRow, FragDecoder.S ) == 1 ) | |||
| { | |||
| // Row already diagonalized exist & ( FragDecoder.MatrixM2B[firstOneInRow][0] ) | |||
| FragExtractLineFromBinaryMatrix( dataTempVector2, firstOneInRow, FragDecoder.Status.FragNbLost ); | |||
| XorParityLine( dataTempVector, dataTempVector2, FragDecoder.Status.FragNbLost ); | |||
| // Have to store it in the mi th position of the missing frag | |||
| li = FragFindMissingIndex( firstOneInRow ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| GetRow( matrixDataTemp, li, FragDecoder.FragSize ); | |||
| #else | |||
| GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize ); | |||
| #endif | |||
| XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize ); | |||
| if( BitArrayIsAllZeros( dataTempVector, FragDecoder.Status.FragNbLost ) ) | |||
| { | |||
| noInfo = 1; | |||
| break; | |||
| } | |||
| firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost ); | |||
| } | |||
| if( noInfo == 0 ) | |||
| { | |||
| FragPushLineToBinaryMatrix( dataTempVector, firstOneInRow, FragDecoder.Status.FragNbLost ); | |||
| li = FragFindMissingIndex( firstOneInRow ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| SetRow( rawData, li, FragDecoder.FragSize ); | |||
| #else | |||
| SetRow( FragDecoder.File, rawData, li, FragDecoder.FragSize ); | |||
| #endif | |||
| SetParity( firstOneInRow, FragDecoder.S, 1 ); | |||
| FragDecoder.M2BLine++; | |||
| } | |||
| if( FragDecoder.M2BLine == FragDecoder.Status.FragNbLost ) | |||
| { | |||
| // Then last step diagonalized | |||
| if( FragDecoder.Status.FragNbLost > 1 ) | |||
| { | |||
| int32_t i, j; | |||
| for( i = ( FragDecoder.Status.FragNbLost - 2 ); i >= 0 ; i-- ) | |||
| { | |||
| li = FragFindMissingIndex( i ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| GetRow( matrixDataTemp, li, FragDecoder.FragSize ); | |||
| #else | |||
| GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize ); | |||
| #endif | |||
| for( j = ( FragDecoder.Status.FragNbLost - 1 ); j > i; j--) | |||
| { | |||
| FragExtractLineFromBinaryMatrix( dataTempVector2, i, FragDecoder.Status.FragNbLost ); | |||
| FragExtractLineFromBinaryMatrix( dataTempVector, j, FragDecoder.Status.FragNbLost ); | |||
| if( GetParity( j, dataTempVector2 ) == 1 ) | |||
| { | |||
| XorParityLine( dataTempVector2, dataTempVector, FragDecoder.Status.FragNbLost ); | |||
| lj = FragFindMissingIndex( j ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| GetRow( rawData, lj, FragDecoder.FragSize ); | |||
| #else | |||
| GetRow( rawData, FragDecoder.File, lj, FragDecoder.FragSize ); | |||
| #endif | |||
| XorDataLine( matrixDataTemp , rawData , FragDecoder.FragSize ); | |||
| } | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| SetRow( matrixDataTemp, li, FragDecoder.FragSize ); | |||
| #else | |||
| SetRow( FragDecoder.File, matrixDataTemp, li, FragDecoder.FragSize ); | |||
| #endif | |||
| } | |||
| return FragDecoder.Status.FragNbLost; | |||
| } | |||
| else | |||
| { | |||
| //If not ( FragDecoder.FragNbLost > 1 ) | |||
| return FragDecoder.Status.FragNbLost; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return FRAG_SESSION_ONGOING; | |||
| } | |||
| FragDecoderStatus_t FragDecoderGetStatus( void ) | |||
| { | |||
| return FragDecoder.Status; | |||
| } | |||
| /* | |||
| *============================================================================= | |||
| * Fragmentation decoder algorithm utilities | |||
| *============================================================================= | |||
| */ | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void SetRow( uint8_t *src, uint16_t row, uint16_t size ) | |||
| { | |||
| if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) ) | |||
| { | |||
| FragDecoder.Callbacks->FragDecoderWrite( row * size, src, size ); | |||
| } | |||
| } | |||
| static void GetRow( uint8_t *dst, uint16_t row, uint16_t size ) | |||
| { | |||
| if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderRead != NULL ) ) | |||
| { | |||
| FragDecoder.Callbacks->FragDecoderRead( row * size, dst, size ); | |||
| } | |||
| } | |||
| #else | |||
| static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ) | |||
| { | |||
| memcpy1( &dst[row * size], src, size ); | |||
| } | |||
| static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ) | |||
| { | |||
| memcpy1( dst, &src[row * size], size ); | |||
| } | |||
| #endif | |||
| static uint8_t GetParity( uint16_t index, uint8_t *matrixRow ) | |||
| { | |||
| uint8_t parity; | |||
| parity = matrixRow[index >> 3]; | |||
| parity = ( parity >> ( 7 - ( index % 8 ) ) ) & 0x01; | |||
| return parity; | |||
| } | |||
| static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity ) | |||
| { | |||
| uint8_t mask = 0xFF - ( 1 << ( 7 - ( index % 8 ) ) ); | |||
| parity = parity << ( 7 - ( index % 8 ) ); | |||
| matrixRow[index >> 3] = ( matrixRow[index >> 3] & mask ) + parity; | |||
| } | |||
| static bool IsPowerOfTwo( uint32_t x ) | |||
| { | |||
| uint8_t sumBit = 0; | |||
| for( uint8_t i = 0; i < 32; i++ ) | |||
| { | |||
| sumBit += ( x & ( 1 << i ) ) >> i; | |||
| } | |||
| if( sumBit == 1 ) | |||
| { | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size ) | |||
| { | |||
| for( int32_t i = 0; i < size; i++ ) | |||
| { | |||
| line1[i] = line1[i] ^ line2[i]; | |||
| } | |||
| } | |||
| static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size ) | |||
| { | |||
| for( int32_t i = 0; i < size; i++ ) | |||
| { | |||
| SetParity( i, line1, ( GetParity( i, line1 ) ^ GetParity( i, line2 ) ) ); | |||
| } | |||
| } | |||
| static int32_t FragPrbs23( int32_t value ) | |||
| { | |||
| int32_t b0 = value & 0x01; | |||
| int32_t b1 = ( value & 0x20 ) >> 5; | |||
| return ( value >> 1 ) + ( ( b0 ^ b1 ) << 22 ); | |||
| } | |||
| static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow ) | |||
| { | |||
| int32_t mTemp; | |||
| int32_t x; | |||
| int32_t nbCoeff = 0; | |||
| int32_t r; | |||
| if( IsPowerOfTwo( m ) != false ) | |||
| { | |||
| mTemp = 1; | |||
| } | |||
| else | |||
| { | |||
| mTemp = 0; | |||
| } | |||
| x = 1 + ( 1001 * n ); | |||
| for( uint16_t i = 0; i < ( ( m >> 3 ) + 1 ); i++ ) | |||
| { | |||
| matrixRow[i] = 0; | |||
| } | |||
| while( nbCoeff < ( m >> 1 ) ) | |||
| { | |||
| r = 1 << 16; | |||
| while( r >= m ) | |||
| { | |||
| x = FragPrbs23( x ); | |||
| r = x % ( m + mTemp ); | |||
| } | |||
| SetParity( r, matrixRow, 1 ); | |||
| nbCoeff += 1; | |||
| } | |||
| } | |||
| static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size ) | |||
| { | |||
| for( uint16_t i = 0; i < size; i++) | |||
| { | |||
| if ( GetParity( i, bitArray ) == 1 ) | |||
| { | |||
| return i; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size ) | |||
| { | |||
| for( uint16_t i = 0; i < size; i++ ) | |||
| { | |||
| if( GetParity( i, bitArray ) == 1 ) | |||
| { | |||
| return 0; | |||
| } | |||
| } | |||
| return 1; | |||
| } | |||
| /*! | |||
| * \brief Finds & marks missing fragments | |||
| * | |||
| * \param [IN] counter Current fragment counter | |||
| * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place | |||
| */ | |||
| static void FragFindMissingFrags( uint16_t counter ) | |||
| { | |||
| int32_t i; | |||
| for( i = FragDecoder.Status.FragNbLastRx; i < ( counter - 1 ); i++ ) | |||
| { | |||
| if( i < FragDecoder.FragNb ) | |||
| { | |||
| FragDecoder.Status.FragNbLost++; | |||
| FragDecoder.FragNbMissingIndex[i] = FragDecoder.Status.FragNbLost; | |||
| } | |||
| } | |||
| if( i < FragDecoder.FragNb ) | |||
| { | |||
| FragDecoder.Status.FragNbLastRx = counter; | |||
| } | |||
| else | |||
| { | |||
| FragDecoder.Status.FragNbLastRx = FragDecoder.FragNb + 1; | |||
| } | |||
| DBG( "RECEIVED : %5d / %5d Fragments\n", FragDecoder.Status.FragNbRx, FragDecoder.FragNb ); | |||
| DBG( " %5d / %5d Bytes\n", FragDecoder.Status.FragNbRx * FragDecoder.FragSize, FragDecoder.FragNb * FragDecoder.FragSize ); | |||
| DBG( "LOST : %7d Fragments\n\n", FragDecoder.Status.FragNbLost ); | |||
| } | |||
| /*! | |||
| * \brief Finds the index (frag counter) of the x th missing frag | |||
| * | |||
| * \param [IN] x x th missing frag | |||
| * | |||
| * \retval counter The counter value associated to the x th missing frag | |||
| */ | |||
| static uint16_t FragFindMissingIndex( uint16_t x ) | |||
| { | |||
| for( uint16_t i = 0; i < FragDecoder.FragNb; i++ ) | |||
| { | |||
| if( FragDecoder.FragNbMissingIndex[i] == ( x + 1 ) ) | |||
| { | |||
| return i; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| /*! | |||
| * \brief Extacts a row from the binary matrix and expands it to a bitArray | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] rowIndex Matrix row index | |||
| * \param [IN] bitsInRow Number of bits in one row | |||
| */ | |||
| static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow ) | |||
| { | |||
| uint32_t findByte = 0; | |||
| uint32_t findBitInByte = 0; | |||
| if( rowIndex > 0 ) | |||
| { | |||
| findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3; | |||
| findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8; | |||
| } | |||
| if( rowIndex > 0 ) | |||
| { | |||
| for( uint16_t i = 0; i < rowIndex; i++ ) | |||
| { | |||
| SetParity( i, bitArray, 0 ); | |||
| } | |||
| } | |||
| for( uint16_t i = rowIndex; i < bitsInRow; i++ ) | |||
| { | |||
| SetParity( i, | |||
| bitArray, | |||
| ( FragDecoder.MatrixM2B[findByte] >> ( 7 - findBitInByte ) ) & 0x01 ); | |||
| findBitInByte++; | |||
| if( findBitInByte == 8 ) | |||
| { | |||
| findBitInByte = 0; | |||
| findByte++; | |||
| } | |||
| } | |||
| } | |||
| /*! | |||
| * \brief Collapses and Pushs a row of a bit array to the matrix | |||
| * | |||
| * \param [IN] bitArray Pointer to the bit array | |||
| * \param [IN] rowIndex Matrix row index | |||
| * \param [IN] bitsInRow Number of bits in one row | |||
| */ | |||
| static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow ) | |||
| { | |||
| uint32_t findByte = 0; | |||
| uint32_t findBitInByte = 0; | |||
| if ( rowIndex > 0) { | |||
| findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3; | |||
| findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8; | |||
| } | |||
| for( uint16_t i = rowIndex; i < bitsInRow; i++ ) | |||
| { | |||
| if( GetParity( i, bitArray ) == 0 ) | |||
| { | |||
| FragDecoder.MatrixM2B[findByte] = FragDecoder.MatrixM2B[findByte] & ( 0xFF - ( 1 << ( 7 - findBitInByte ) ) ); | |||
| } | |||
| findBitInByte++; | |||
| if( findBitInByte == 8 ) | |||
| { | |||
| findBitInByte = 0; | |||
| findByte++; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,143 @@ | |||
| /*! | |||
| * \file FragDecoder.h | |||
| * | |||
| * \brief Implements the LoRa-Alliance fragmentation decoder | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Fabien Holin ( Semtech ) | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __FRAG_DECODER_H__ | |||
| #define __FRAG_DECODER_H__ | |||
| #include <stdint.h> | |||
| /*! | |||
| * If set to 1 the new API defining \ref FragDecoderWrite and | |||
| * \ref FragDecoderReadfunction callbacks is used. | |||
| */ | |||
| #define FRAG_DECODER_FILE_HANDLING_NEW_API 1 | |||
| /*! | |||
| * Maximum number of fragment that can be handled. | |||
| * | |||
| * \remark This parameter has an impact on the memory footprint. | |||
| */ | |||
| #define FRAG_MAX_NB 21 | |||
| /*! | |||
| * Maximum fragment size that can be handled. | |||
| * | |||
| * \remark This parameter has an impact on the memory footprint. | |||
| */ | |||
| #define FRAG_MAX_SIZE 50 | |||
| /*! | |||
| * Maximum number of extra frames that can be handled. | |||
| * | |||
| * \remark This parameter has an impact on the memory footprint. | |||
| */ | |||
| #define FRAG_MAX_REDUNDANCY 5 | |||
| #define FRAG_SESSION_FINISHED ( int32_t )0 | |||
| #define FRAG_SESSION_NOT_STARTED ( int32_t )-2 | |||
| #define FRAG_SESSION_ONGOING ( int32_t )-1 | |||
| typedef struct sFragDecoderStatus | |||
| { | |||
| uint16_t FragNbRx; | |||
| uint16_t FragNbLost; | |||
| uint16_t FragNbLastRx; | |||
| uint8_t MatrixError; | |||
| }FragDecoderStatus_t; | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| typedef struct sFragDecoderCallbacks | |||
| { | |||
| /*! | |||
| * Writes `data` buffer of `size` starting at address `addr` | |||
| * | |||
| * \param [IN] addr Address start index to write to. | |||
| * \param [IN] data Data buffer to be written. | |||
| * \param [IN] size Size of data buffer to be written. | |||
| * | |||
| * \retval status Write operation status [0: Success, -1 Fail] | |||
| */ | |||
| int8_t ( *FragDecoderWrite )( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| /*! | |||
| * Reads `data` buffer of `size` starting at address `addr` | |||
| * | |||
| * \param [IN] addr Address start index to read from. | |||
| * \param [IN] data Data buffer to be read. | |||
| * \param [IN] size Size of data buffer to be read. | |||
| * | |||
| * \retval status Read operation status [0: Success, -1 Fail] | |||
| */ | |||
| int8_t ( *FragDecoderRead )( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| }FragDecoderCallbacks_t; | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * \brief Initializes the fragmentation decoder | |||
| * | |||
| * \param [IN] fragNb Number of expected fragments (without redundancy packets) | |||
| * \param [IN] fragSize Size of a fragment | |||
| * \param [IN] callbacks Pointer to the Write/Read functions. | |||
| */ | |||
| void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks ); | |||
| #else | |||
| /*! | |||
| * \brief Initializes the fragmentation decoder | |||
| * | |||
| * \param [IN] fragNb Number of expected fragments (without redundancy packets) | |||
| * \param [IN] fragSize Size of a fragment | |||
| * \param [IN] file Pointer to file buffer size | |||
| * \param [IN] fileSize File buffer size | |||
| */ | |||
| void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * \brief Gets the maximum file size that can be received | |||
| * | |||
| * \retval size FileSize | |||
| */ | |||
| uint32_t FragDecoderGetMaxFileSize( void ); | |||
| #endif | |||
| /*! | |||
| * \brief Function to decode and reconstruct the binary file | |||
| * Called for each receive frame | |||
| * | |||
| * \param [IN] fragCounter Fragment counter [1..(FragDecoder.FragNb + FragDecoder.Redundancy)] | |||
| * \param [IN] rawData Pointer to the fragment to be processed (length = FragDecoder.FragSize) | |||
| * | |||
| * \retval status Process status. [FRAG_SESSION_ONGOING, | |||
| * FRAG_SESSION_FINISHED or | |||
| * FragDecoder.Status.FragNbLost] | |||
| */ | |||
| int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData ); | |||
| /*! | |||
| * \brief Gets the current fragmentation status | |||
| * | |||
| * \retval status Fragmentation decoder status | |||
| */ | |||
| FragDecoderStatus_t FragDecoderGetStatus( void ); | |||
| #endif // __FRAG_DECODER_H__ | |||
| @@ -0,0 +1,146 @@ | |||
| /*! | |||
| * \file LmPackage.h | |||
| * | |||
| * \brief Defines the packages API | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMH_PACKAGE_H__ | |||
| #define __LMH_PACKAGE_H__ | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #include "LmHandlerTypes.h" | |||
| /*! | |||
| * Maximum number of packages | |||
| */ | |||
| #define PKG_MAX_NUMBER 4 | |||
| typedef struct LmhPackage_s | |||
| { | |||
| uint8_t Port; | |||
| /* | |||
| *========================================================================= | |||
| * Below callbacks must be initialized in package variable declaration | |||
| *========================================================================= | |||
| */ | |||
| /*! | |||
| * Initializes the package with provided parameters | |||
| * | |||
| * \param [IN] params Pointer to the package parameters | |||
| * \param [IN] dataBuffer Pointer to main application buffer | |||
| * \param [IN] dataBufferMaxSize Main application buffer maximum size | |||
| */ | |||
| void ( *Init )( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); | |||
| /*! | |||
| * Returns the current package initialization status. | |||
| * | |||
| * \retval status Package initialization status | |||
| * [true: Initialized, false: Not initialized] | |||
| */ | |||
| bool ( *IsInitialized )( void ); | |||
| /*! | |||
| * Returns if a package transmission is pending or not. | |||
| * | |||
| * \retval status Package transmission status | |||
| * [true: pending, false: Not pending] | |||
| */ | |||
| bool ( *IsTxPending )( void ); | |||
| /*! | |||
| * Processes the internal package events. | |||
| */ | |||
| void ( *Process )( void ); | |||
| /*! | |||
| * Processes the MCSP Confirm | |||
| * | |||
| * \param [IN] mcpsConfirm MCPS confirmation primitive data | |||
| */ | |||
| void ( *OnMcpsConfirmProcess )( McpsConfirm_t *mcpsConfirm ); | |||
| /*! | |||
| * Processes the MCPS Indication | |||
| * | |||
| * \param [IN] mcpsIndication MCPS indication primitive data | |||
| */ | |||
| void ( *OnMcpsIndicationProcess )( McpsIndication_t *mcpsIndication ); | |||
| /*! | |||
| * Processes the MLME Confirm | |||
| * | |||
| * \param [IN] mlmeConfirm MLME confirmation primitive data | |||
| */ | |||
| void ( *OnMlmeConfirmProcess )( MlmeConfirm_t *mlmeConfirm ); | |||
| /*! | |||
| * Processes the MLME Indication | |||
| * | |||
| * \param [IN] mlmeIndication MLME indication primitive data | |||
| */ | |||
| void ( *OnMlmeIndicationProcess )( MlmeIndication_t *mlmeIndication ); | |||
| /* | |||
| *========================================================================= | |||
| * Below callbacks must be initialized in LmHandler initialization with | |||
| * provideded LmHandlerSend and OnMacRequest functions | |||
| *========================================================================= | |||
| */ | |||
| /*! | |||
| * Notifies the upper layer that a MCPS request has been made to the MAC layer | |||
| * | |||
| * \param [IN] status - Request returned status | |||
| * \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t. | |||
| * \param [IN] nextTxDelay - Time to wait until another TX is possible. | |||
| */ | |||
| void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay ); | |||
| /*! | |||
| * Notifies the upper layer that a MLME request has been made to the MAC layer | |||
| * | |||
| * \param [IN] status - Request returned status | |||
| * \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t. | |||
| * \param [IN] nextTxDelay - Time to wait until another TX is possible. | |||
| */ | |||
| void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay ); | |||
| /*! | |||
| * Join a LoRa Network in classA | |||
| * | |||
| * \Note if the device is ABP, this is a pass through function | |||
| * | |||
| * \param [IN] isOtaa Indicates which activation mode must be used | |||
| */ | |||
| void ( *OnJoinRequest )( bool isOtaa ); | |||
| /*! | |||
| * Requests network server time update | |||
| * | |||
| * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET | |||
| */ | |||
| LmHandlerErrorStatus_t ( *OnDeviceTimeRequest )( void ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| /*! | |||
| * Notifies the upper layer that the system time has been updated. | |||
| * | |||
| * \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second | |||
| * \param [in] timeCorrection Received time correction value | |||
| */ | |||
| void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| /*! | |||
| * Notifies the upper layer that the system time has been updated. | |||
| */ | |||
| void ( *OnSysTimeUpdate )( void ); | |||
| #endif | |||
| }LmhPackage_t; | |||
| #endif // __LMH_PACKAGE_H__ | |||
| @@ -0,0 +1,372 @@ | |||
| /*! | |||
| * \file LmhpClockSync.c | |||
| * | |||
| * \brief Implements the LoRa-Alliance clock synchronization package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include "LmHandler.h" | |||
| #include "LmhpClockSync.h" | |||
| /*! | |||
| * LoRaWAN Application Layer Clock Synchronization Specification | |||
| */ | |||
| #define CLOCK_SYNC_PORT 202 | |||
| #define CLOCK_SYNC_ID 1 | |||
| #define CLOCK_SYNC_VERSION 1 | |||
| /*! | |||
| * Package current context | |||
| */ | |||
| typedef struct LmhpClockSyncState_s | |||
| { | |||
| bool Initialized; | |||
| bool IsTxPending; | |||
| uint8_t DataBufferMaxSize; | |||
| uint8_t *DataBuffer; | |||
| union | |||
| { | |||
| uint8_t Value; | |||
| struct | |||
| { | |||
| uint8_t TokenReq: 4; | |||
| uint8_t AnsRequired: 1; | |||
| uint8_t RFU: 3; | |||
| }Fields; | |||
| }TimeReqParam; | |||
| bool AppTimeReqPending; | |||
| bool AdrEnabledPrev; | |||
| uint8_t NbTransPrev; | |||
| uint8_t DataratePrev; | |||
| uint8_t NbTransmissions; | |||
| }LmhpClockSyncState_t; | |||
| typedef enum LmhpClockSyncMoteCmd_e | |||
| { | |||
| CLOCK_SYNC_PKG_VERSION_ANS = 0x00, | |||
| CLOCK_SYNC_APP_TIME_REQ = 0x01, | |||
| CLOCK_SYNC_APP_TIME_PERIOD_ANS = 0x02, | |||
| CLOCK_SYNC_FORCE_RESYNC_ANS = 0x03, | |||
| }LmhpClockSyncMoteCmd_t; | |||
| typedef enum LmhpClockSyncSrvCmd_e | |||
| { | |||
| CLOCK_SYNC_PKG_VERSION_REQ = 0x00, | |||
| CLOCK_SYNC_APP_TIME_ANS = 0x01, | |||
| CLOCK_SYNC_APP_TIME_PERIOD_REQ = 0x02, | |||
| CLOCK_SYNC_FORCE_RESYNC_REQ = 0x03, | |||
| }LmhpClockSyncSrvCmd_t; | |||
| /*! | |||
| * Initializes the package with provided parameters | |||
| * | |||
| * \param [IN] params Pointer to the package parameters | |||
| * \param [IN] dataBuffer Pointer to main application buffer | |||
| * \param [IN] dataBufferMaxSize Main application buffer maximum size | |||
| */ | |||
| static void LmhpClockSyncInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); | |||
| /*! | |||
| * Returns the current package initialization status. | |||
| * | |||
| * \retval status Package initialization status | |||
| * [true: Initialized, false: Not initialized] | |||
| */ | |||
| static bool LmhpClockSyncIsInitialized( void ); | |||
| /*! | |||
| * Returns if a package transmission is pending or not. | |||
| * | |||
| * \retval status Package transmission status | |||
| * [true: pending, false: Not pending] | |||
| */ | |||
| static bool LmhpClockSyncIsTxPending( void ); | |||
| /*! | |||
| * Processes the internal package events. | |||
| */ | |||
| static void LmhpClockSyncProcess( void ); | |||
| /*! | |||
| * Processes the MCSP Confirm | |||
| * | |||
| * \param [IN] mcpsConfirm MCPS confirmation primitive data | |||
| */ | |||
| static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm ); | |||
| /*! | |||
| * Processes the MCPS Indication | |||
| * | |||
| * \param [IN] mcpsIndication MCPS indication primitive data | |||
| */ | |||
| static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication ); | |||
| static LmhpClockSyncState_t LmhpClockSyncState = | |||
| { | |||
| .Initialized = false, | |||
| .IsTxPending = false, | |||
| .TimeReqParam.Value = 0, | |||
| .AppTimeReqPending = false, | |||
| .AdrEnabledPrev = false, | |||
| .NbTransPrev = 0, | |||
| .NbTransmissions = 0, | |||
| }; | |||
| static LmhPackage_t LmhpClockSyncPackage = | |||
| { | |||
| .Port = CLOCK_SYNC_PORT, | |||
| .Init = LmhpClockSyncInit, | |||
| .IsInitialized = LmhpClockSyncIsInitialized, | |||
| .IsTxPending = LmhpClockSyncIsTxPending, | |||
| .Process = LmhpClockSyncProcess, | |||
| .OnMcpsConfirmProcess = LmhpClockSyncOnMcpsConfirm, | |||
| .OnMcpsIndicationProcess = LmhpClockSyncOnMcpsIndication, | |||
| .OnMlmeConfirmProcess = NULL, // Not used in this package | |||
| .OnMlmeIndicationProcess = NULL, // Not used in this package | |||
| .OnMacMcpsRequest = NULL, // To be initialized by LmHandler | |||
| .OnMacMlmeRequest = NULL, // To be initialized by LmHandler | |||
| .OnJoinRequest = NULL, // To be initialized by LmHandler | |||
| .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler | |||
| .OnSysTimeUpdate = NULL, // To be initialized by LmHandler | |||
| }; | |||
| LmhPackage_t *LmphClockSyncPackageFactory( void ) | |||
| { | |||
| return &LmhpClockSyncPackage; | |||
| } | |||
| static void LmhpClockSyncInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) | |||
| { | |||
| if( dataBuffer != NULL ) | |||
| { | |||
| LmhpClockSyncState.DataBuffer = dataBuffer; | |||
| LmhpClockSyncState.DataBufferMaxSize = dataBufferMaxSize; | |||
| LmhpClockSyncState.Initialized = true; | |||
| } | |||
| else | |||
| { | |||
| LmhpClockSyncState.Initialized = false; | |||
| } | |||
| LmhpClockSyncState.IsTxPending = false; | |||
| } | |||
| static bool LmhpClockSyncIsInitialized( void ) | |||
| { | |||
| return LmhpClockSyncState.Initialized; | |||
| } | |||
| static bool LmhpClockSyncIsTxPending( void ) | |||
| { | |||
| return LmhpClockSyncState.IsTxPending; | |||
| } | |||
| static void LmhpClockSyncProcess( void ) | |||
| { | |||
| if( LmhpClockSyncState.NbTransmissions > 0 ) | |||
| { | |||
| if( LmhpClockSyncAppTimeReq( ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| LmhpClockSyncState.NbTransmissions--; | |||
| } | |||
| } | |||
| } | |||
| static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm ) | |||
| { | |||
| MibRequestConfirm_t mibReq; | |||
| if( LmhpClockSyncState.AppTimeReqPending == true ) | |||
| { | |||
| // Revert ADR setting | |||
| mibReq.Type = MIB_ADR; | |||
| mibReq.Param.AdrEnable = LmhpClockSyncState.AdrEnabledPrev; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| // Revert NbTrans setting | |||
| mibReq.Type = MIB_CHANNELS_NB_TRANS; | |||
| mibReq.Param.ChannelsNbTrans = LmhpClockSyncState.NbTransPrev; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| // Revert data rate setting | |||
| mibReq.Type = MIB_CHANNELS_DATARATE; | |||
| mibReq.Param.ChannelsDatarate = LmhpClockSyncState.DataratePrev; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| LmhpClockSyncState.AppTimeReqPending = false; | |||
| } | |||
| } | |||
| static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication ) | |||
| { | |||
| uint8_t cmdIndex = 0; | |||
| uint8_t dataBufferIndex = 0; | |||
| if( mcpsIndication->Port != CLOCK_SYNC_PORT ) | |||
| { | |||
| return; | |||
| } | |||
| while( cmdIndex < mcpsIndication->BufferSize ) | |||
| { | |||
| switch( mcpsIndication->Buffer[cmdIndex++] ) | |||
| { | |||
| case CLOCK_SYNC_PKG_VERSION_REQ: | |||
| { | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_PKG_VERSION_ANS; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_ID; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_VERSION; | |||
| break; | |||
| } | |||
| case CLOCK_SYNC_APP_TIME_ANS: | |||
| { | |||
| LmhpClockSyncState.NbTransmissions = 0; | |||
| // Check if a more precise time correction has been received. | |||
| // If yes then don't process and ignore this answer. | |||
| if( mcpsIndication->DeviceTimeAnsReceived == true ) | |||
| { | |||
| cmdIndex += 5; | |||
| break; | |||
| } | |||
| int32_t timeCorrection = 0; | |||
| timeCorrection = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| if( ( mcpsIndication->Buffer[cmdIndex++] & 0x0F ) == LmhpClockSyncState.TimeReqParam.Fields.TokenReq ) | |||
| { | |||
| SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 }; | |||
| curTime = SysTimeGet( ); | |||
| curTime.Seconds += timeCorrection; | |||
| SysTimeSet( curTime ); | |||
| LmhpClockSyncState.TimeReqParam.Fields.TokenReq = ( LmhpClockSyncState.TimeReqParam.Fields.TokenReq + 1 ) & 0x0F; | |||
| if( LmhpClockSyncPackage.OnSysTimeUpdate != NULL ) | |||
| { | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| LmhpClockSyncPackage.OnSysTimeUpdate( | |||
| ( timeCorrection >= -1 ) && ( timeCorrection <= 1 ), | |||
| timeCorrection ); | |||
| #else | |||
| if( ( timeCorrection >= -1 ) && ( timeCorrection <= 1 ) ) | |||
| { | |||
| LmhpClockSyncPackage.OnSysTimeUpdate( ); | |||
| } | |||
| #endif | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| case CLOCK_SYNC_APP_TIME_PERIOD_REQ: | |||
| { | |||
| // Increment index | |||
| cmdIndex++; | |||
| // TODO implement command prosessing and handling | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_PERIOD_ANS; | |||
| // Answer status not supported. | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = 0x01; | |||
| SysTime_t curTime = SysTimeGet( ); | |||
| // Substract Unix to Gps epcoh offset. The system time is based on Unix time. | |||
| curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF; | |||
| break; | |||
| } | |||
| case CLOCK_SYNC_FORCE_RESYNC_REQ: | |||
| { | |||
| LmhpClockSyncState.NbTransmissions = mcpsIndication->Buffer[cmdIndex++] & 0X07; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if( dataBufferIndex != 0 ) | |||
| { | |||
| // Answer commands | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = LmhpClockSyncState.DataBuffer, | |||
| .BufferSize = dataBufferIndex, | |||
| .Port = CLOCK_SYNC_PORT | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| } | |||
| LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return LORAMAC_HANDLER_ERROR; | |||
| } | |||
| if( LmhpClockSyncState.AppTimeReqPending == false ) | |||
| { | |||
| MibRequestConfirm_t mibReq; | |||
| // Disable ADR | |||
| mibReq.Type = MIB_ADR; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| LmhpClockSyncState.AdrEnabledPrev = mibReq.Param.AdrEnable; | |||
| mibReq.Param.AdrEnable = false; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| // Set NbTrans = 1 | |||
| mibReq.Type = MIB_CHANNELS_NB_TRANS; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| LmhpClockSyncState.NbTransPrev = mibReq.Param.ChannelsNbTrans; | |||
| mibReq.Param.ChannelsNbTrans = 1; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| // Store data rate | |||
| mibReq.Type = MIB_CHANNELS_DATARATE; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| LmhpClockSyncState.DataratePrev = mibReq.Param.ChannelsDatarate; | |||
| // Add DeviceTimeReq MAC command. | |||
| // In case the network server supports this more precise command | |||
| // this package will use DeviceTimeAns answer as clock synchronization | |||
| // mechanism. | |||
| LmhpClockSyncPackage.OnDeviceTimeRequest( ); | |||
| } | |||
| SysTime_t curTime = SysTimeGet( ); | |||
| uint8_t dataBufferIndex = 0; | |||
| // Substract Unix to Gps epcoh offset. The system time is based on Unix time. | |||
| curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_REQ; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF; | |||
| LmhpClockSyncState.TimeReqParam.Fields.AnsRequired = 0; | |||
| LmhpClockSyncState.DataBuffer[dataBufferIndex++] = LmhpClockSyncState.TimeReqParam.Value; | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = LmhpClockSyncState.DataBuffer, | |||
| .BufferSize = dataBufferIndex, | |||
| .Port = CLOCK_SYNC_PORT | |||
| }; | |||
| LmhpClockSyncState.AppTimeReqPending = true; | |||
| return LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| /*! | |||
| * \file LmhpClockSync.h | |||
| * | |||
| * \brief Implements the LoRa-Alliance clock synchronization package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMHP_CLOCK_SYNC_H__ | |||
| #define __LMHP_CLOCK_SYNC_H__ | |||
| #include "LoRaMac.h" | |||
| #include "LmHandlerTypes.h" | |||
| #include "LmhPackage.h" | |||
| /*! | |||
| * Clock sync package identifier. | |||
| * | |||
| * \remark This value must be unique amongst the packages | |||
| */ | |||
| #define PACKAGE_ID_CLOCK_SYNC 1 | |||
| /*! | |||
| * Clock sync package parameters | |||
| * | |||
| * This package doesn't require parameters | |||
| */ | |||
| //typedef struct LmphClockSyncParams_s | |||
| //{ | |||
| //}LmphClockSyncParams_t; | |||
| LmhPackage_t *LmphClockSyncPackageFactory( void ); | |||
| LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void ); | |||
| #endif // __LMHP_CLOCK_SYNC_H__ | |||
| @@ -0,0 +1,590 @@ | |||
| /*! | |||
| * \file LmhpCompliance.c | |||
| * | |||
| * \brief Implements the LoRa-Alliance certification protocol handling | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #include "board.h" | |||
| #include "NvmDataMgmt.h" | |||
| #include "LoRaMacTest.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| /*! | |||
| * LoRaWAN compliance certification protocol port number. | |||
| * | |||
| * LoRaWAN Specification V1.x.x, chapter 4.3.2 | |||
| */ | |||
| #define COMPLIANCE_PORT 224 | |||
| #define COMPLIANCE_ID 6 | |||
| #define COMPLIANCE_VERSION 1 | |||
| typedef struct ClassBStatus_s | |||
| { | |||
| bool IsBeaconRxOn; | |||
| uint8_t PingSlotPeriodicity; | |||
| uint16_t BeaconCnt; | |||
| BeaconInfo_t Info; | |||
| } ClassBStatus_t; | |||
| /*! | |||
| * LoRaWAN compliance tests support data | |||
| */ | |||
| typedef struct ComplianceTestState_s | |||
| { | |||
| bool Initialized; | |||
| bool IsTxPending; | |||
| TimerTime_t TxPendingTimestamp; | |||
| LmHandlerMsgTypes_t IsTxConfirmed; | |||
| uint8_t DataBufferMaxSize; | |||
| uint8_t DataBufferSize; | |||
| uint8_t* DataBuffer; | |||
| uint16_t RxAppCnt; | |||
| ClassBStatus_t ClassBStatus; | |||
| bool IsResetCmdPending; | |||
| } ComplianceTestState_t; | |||
| typedef enum ComplianceMoteCmd_e | |||
| { | |||
| COMPLIANCE_PKG_VERSION_ANS = 0x00, | |||
| COMPLIANCE_ECHO_PAYLOAD_ANS = 0x08, | |||
| COMPLIANCE_RX_APP_CNT_ANS = 0x09, | |||
| COMPLIANCE_BEACON_RX_STATUS_IND = 0x40, | |||
| COMPLIANCE_BEACON_CNT_ANS = 0x41, | |||
| COMPLIANCE_DUT_VERSION_ANS = 0x7F, | |||
| } ComplianceMoteCmd_t; | |||
| typedef enum ComplianceSrvCmd_e | |||
| { | |||
| COMPLIANCE_PKG_VERSION_REQ = 0x00, | |||
| COMPLIANCE_DUT_RESET_REQ = 0x01, | |||
| COMPLIANCE_DUT_JOIN_REQ = 0x02, | |||
| COMPLIANCE_SWITCH_CLASS_REQ = 0x03, | |||
| COMPLIANCE_ADR_BIT_CHANGE_REQ = 0x04, | |||
| COMPLIANCE_REGIONAL_DUTY_CYCLE_CTRL_REQ = 0x05, | |||
| COMPLIANCE_TX_PERIODICITY_CHANGE_REQ = 0x06, | |||
| COMPLIANCE_TX_FRAMES_CTRL_REQ = 0x07, | |||
| COMPLIANCE_ECHO_PAYLOAD_REQ = 0x08, | |||
| COMPLIANCE_RX_APP_CNT_REQ = 0x09, | |||
| COMPLIANCE_RX_APP_CNT_RESET_REQ = 0x0A, | |||
| COMPLIANCE_LINK_CHECK_REQ = 0x20, | |||
| COMPLIANCE_DEVICE_TIME_REQ = 0x21, | |||
| COMPLIANCE_PING_SLOT_INFO_REQ = 0x22, | |||
| COMPLIANCE_BEACON_CNT_REQ = 0x41, | |||
| COMPLIANCE_BEACON_CNT_RESET_REQ = 0x42, | |||
| COMPLIANCE_TX_CW_REQ = 0x7D, | |||
| COMPLIANCE_DUT_FPORT_224_DISABLE_REQ = 0x7E, | |||
| COMPLIANCE_DUT_VERSION_REQ = 0x7F, | |||
| } ComplianceSrvCmd_t; | |||
| /*! | |||
| * Holds the compliance test current context | |||
| */ | |||
| static ComplianceTestState_t ComplianceTestState = { | |||
| .Initialized = false, | |||
| .IsTxPending = false, | |||
| .TxPendingTimestamp = 0, | |||
| .IsTxConfirmed = LORAMAC_HANDLER_UNCONFIRMED_MSG, | |||
| .DataBufferMaxSize = 0, | |||
| .DataBufferSize = 0, | |||
| .DataBuffer = NULL, | |||
| .RxAppCnt = 0, | |||
| .ClassBStatus = { 0 }, | |||
| .IsResetCmdPending = false, | |||
| }; | |||
| /*! | |||
| * LoRaWAN compliance tests protocol handler parameters | |||
| */ | |||
| static LmhpComplianceParams_t* ComplianceParams; | |||
| /*! | |||
| * Reset Beacon status structure | |||
| */ | |||
| static inline void ClassBStatusReset( void ) | |||
| { | |||
| memset1( ( uint8_t* ) &ComplianceTestState.ClassBStatus, 0, sizeof( ClassBStatus_t ) / sizeof( uint8_t ) ); | |||
| } | |||
| /*! | |||
| * Initializes the compliance tests with provided parameters | |||
| * | |||
| * \param [IN] params Structure containing the initial compliance | |||
| * tests parameters. | |||
| * \param [IN] dataBuffer Pointer to main application buffer | |||
| * \param [IN] dataBufferMaxSize Application buffer maximum size | |||
| */ | |||
| static void LmhpComplianceInit( void* params, uint8_t* dataBuffer, uint8_t dataBufferMaxSize ); | |||
| /*! | |||
| * Returns the current compliance certification protocol initialization status. | |||
| * | |||
| * \retval status Compliance certification protocol initialization status | |||
| * [true: Initialized, false: Not initialized] | |||
| */ | |||
| static bool LmhpComplianceIsInitialized( void ); | |||
| /*! | |||
| * Returns if a package transmission is pending or not. | |||
| * | |||
| * \retval status Package transmission status | |||
| * [true: pending, false: Not pending] | |||
| */ | |||
| static bool LmhpComplianceIsTxPending( void ); | |||
| /*! | |||
| * Processes the LoRaMac Compliance events. | |||
| */ | |||
| static void LmhpComplianceProcess( void ); | |||
| /*! | |||
| * Processes the MCPS Indication | |||
| * | |||
| * \param [IN] mcpsIndication MCPS indication primitive data | |||
| */ | |||
| static void LmhpComplianceOnMcpsIndication( McpsIndication_t* mcpsIndication ); | |||
| /*! | |||
| * Processes the MLME Confirm | |||
| * | |||
| * \param [IN] mlmeConfirm MLME confirmation primitive data | |||
| */ | |||
| static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm ); | |||
| /*! | |||
| * Processes the MLME Indication | |||
| * | |||
| * \param [IN] mlmeIndication MLME indication primitive data | |||
| */ | |||
| static void LmhpComplianceOnMlmeIndication( MlmeIndication_t* mlmeIndication ); | |||
| /*! | |||
| * Helper function to send the BeaconRxStatusInd message | |||
| */ | |||
| static void SendBeaconRxStatusInd( void ); | |||
| LmhPackage_t CompliancePackage = { | |||
| .Port = COMPLIANCE_PORT, | |||
| .Init = LmhpComplianceInit, | |||
| .IsInitialized = LmhpComplianceIsInitialized, | |||
| .IsTxPending = LmhpComplianceIsTxPending, | |||
| .Process = LmhpComplianceProcess, | |||
| .OnMcpsConfirmProcess = NULL, // Not used in this package | |||
| .OnMcpsIndicationProcess = LmhpComplianceOnMcpsIndication, | |||
| .OnMlmeConfirmProcess = LmhpComplianceOnMlmeConfirm, | |||
| .OnMlmeIndicationProcess = LmhpComplianceOnMlmeIndication, | |||
| .OnMacMcpsRequest = NULL, // To be initialized by LmHandler | |||
| .OnMacMlmeRequest = NULL, // To be initialized by LmHandler | |||
| .OnJoinRequest = NULL, // To be initialized by LmHandler | |||
| .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler | |||
| .OnSysTimeUpdate = NULL, // To be initialized by LmHandler | |||
| }; | |||
| LmhPackage_t* LmphCompliancePackageFactory( void ) | |||
| { | |||
| return &CompliancePackage; | |||
| } | |||
| static void LmhpComplianceInit( void* params, uint8_t* dataBuffer, uint8_t dataBufferMaxSize ) | |||
| { | |||
| if( ( params != NULL ) && ( dataBuffer != NULL ) ) | |||
| { | |||
| ComplianceParams = ( LmhpComplianceParams_t* ) params; | |||
| ComplianceTestState.DataBuffer = dataBuffer; | |||
| ComplianceTestState.DataBufferMaxSize = dataBufferMaxSize; | |||
| ComplianceTestState.Initialized = true; | |||
| } | |||
| else | |||
| { | |||
| ComplianceParams = NULL; | |||
| ComplianceTestState.Initialized = false; | |||
| } | |||
| ComplianceTestState.RxAppCnt = 0; | |||
| ClassBStatusReset( ); | |||
| ComplianceTestState.IsTxPending = false; | |||
| ComplianceTestState.IsResetCmdPending = false; | |||
| } | |||
| static bool LmhpComplianceIsInitialized( void ) | |||
| { | |||
| return ComplianceTestState.Initialized; | |||
| } | |||
| static bool LmhpComplianceIsTxPending( void ) | |||
| { | |||
| return ComplianceTestState.IsTxPending; | |||
| } | |||
| static void LmhpComplianceProcess( void ) | |||
| { | |||
| if( ComplianceTestState.IsTxPending == true ) | |||
| { | |||
| TimerTime_t now = TimerGetCurrentTime( ); | |||
| if( now > ( ComplianceTestState.TxPendingTimestamp + LmHandlerGetDutyCycleWaitTime( ) ) ) | |||
| { | |||
| if( ComplianceTestState.DataBufferSize != 0 ) | |||
| { | |||
| // Answer commands | |||
| LmHandlerAppData_t appData = { | |||
| .Buffer = ComplianceTestState.DataBuffer, | |||
| .BufferSize = ComplianceTestState.DataBufferSize, | |||
| .Port = COMPLIANCE_PORT, | |||
| }; | |||
| if( LmHandlerSend( &appData, ComplianceTestState.IsTxConfirmed ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // try to send the message again | |||
| ComplianceTestState.IsTxPending = true; | |||
| } | |||
| else | |||
| { | |||
| ComplianceTestState.IsTxPending = false; | |||
| } | |||
| ComplianceTestState.TxPendingTimestamp = now; | |||
| } | |||
| } | |||
| } | |||
| if( ComplianceTestState.IsResetCmdPending == true ) | |||
| { | |||
| ComplianceTestState.IsResetCmdPending = false; | |||
| // Call platform MCU reset API | |||
| BoardResetMcu( ); | |||
| } | |||
| } | |||
| static void LmhpComplianceOnMcpsIndication( McpsIndication_t* mcpsIndication ) | |||
| { | |||
| uint8_t cmdIndex = 0; | |||
| MibRequestConfirm_t mibReq; | |||
| if( ComplianceTestState.Initialized == false ) | |||
| { | |||
| return; | |||
| } | |||
| // Increment the compliance certification protocol downlink counter | |||
| // Not counting downlinks on FPort 0 | |||
| if( ( mcpsIndication->Port > 0 ) || ( mcpsIndication->AckReceived == true ) ) | |||
| { | |||
| ComplianceTestState.RxAppCnt++; | |||
| } | |||
| if( mcpsIndication->RxData == false ) | |||
| { | |||
| return; | |||
| } | |||
| if( mcpsIndication->Port != COMPLIANCE_PORT ) | |||
| { | |||
| return; | |||
| } | |||
| ComplianceTestState.DataBufferSize = 0; | |||
| switch( mcpsIndication->Buffer[cmdIndex++] ) | |||
| { | |||
| case COMPLIANCE_PKG_VERSION_REQ: | |||
| { | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_PKG_VERSION_ANS; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_ID; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_VERSION; | |||
| break; | |||
| } | |||
| case COMPLIANCE_DUT_RESET_REQ: | |||
| { | |||
| ComplianceTestState.IsResetCmdPending = true; | |||
| break; | |||
| } | |||
| case COMPLIANCE_DUT_JOIN_REQ: | |||
| { | |||
| CompliancePackage.OnJoinRequest( true ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_SWITCH_CLASS_REQ: | |||
| { | |||
| MibRequestConfirm_t mibReq; | |||
| mibReq.Type = MIB_DEVICE_CLASS; | |||
| // CLASS_A = 0, CLASS_B = 1, CLASS_C = 2 | |||
| mibReq.Param.Class = ( DeviceClass_t ) mcpsIndication->Buffer[cmdIndex++]; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_ADR_BIT_CHANGE_REQ: | |||
| { | |||
| MibRequestConfirm_t mibReq; | |||
| mibReq.Type = MIB_ADR; | |||
| mibReq.Param.AdrEnable = mcpsIndication->Buffer[cmdIndex++]; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_REGIONAL_DUTY_CYCLE_CTRL_REQ: | |||
| { | |||
| LoRaMacTestSetDutyCycleOn( mcpsIndication->Buffer[cmdIndex++] ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_TX_PERIODICITY_CHANGE_REQ: | |||
| { | |||
| // Periodicity in milli-seconds | |||
| uint32_t periodicity[] = { 0, 5000, 10000, 20000, 30000, 40000, 50000, 60000, 120000, 240000, 480000 }; | |||
| uint8_t index = mcpsIndication->Buffer[cmdIndex++]; | |||
| if( index < ( sizeof( periodicity ) / sizeof( uint32_t ) ) ) | |||
| { | |||
| if( ComplianceParams->OnTxPeriodicityChanged != NULL ) | |||
| { | |||
| ComplianceParams->OnTxPeriodicityChanged( periodicity[index] ); | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| case COMPLIANCE_TX_FRAMES_CTRL_REQ: | |||
| { | |||
| uint8_t frameType = mcpsIndication->Buffer[cmdIndex++]; | |||
| if( ( frameType == 1 ) || ( frameType == 2 ) ) | |||
| { | |||
| ComplianceTestState.IsTxConfirmed = ( frameType != 1 ) ? LORAMAC_HANDLER_CONFIRMED_MSG : LORAMAC_HANDLER_UNCONFIRMED_MSG; | |||
| ComplianceParams->OnTxFrameCtrlChanged( ComplianceTestState.IsTxConfirmed ); | |||
| } | |||
| break; | |||
| } | |||
| case COMPLIANCE_ECHO_PAYLOAD_REQ: | |||
| { | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_ECHO_PAYLOAD_ANS; | |||
| for( uint8_t i = 1; i < MIN( mcpsIndication->BufferSize, ComplianceTestState.DataBufferMaxSize ); | |||
| i++ ) | |||
| { | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = mcpsIndication->Buffer[cmdIndex++] + 1; | |||
| } | |||
| break; | |||
| } | |||
| case COMPLIANCE_RX_APP_CNT_REQ: | |||
| { | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_RX_APP_CNT_ANS; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceTestState.RxAppCnt; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceTestState.RxAppCnt >> 8; | |||
| break; | |||
| } | |||
| case COMPLIANCE_RX_APP_CNT_RESET_REQ: | |||
| { | |||
| ComplianceTestState.RxAppCnt = 0; | |||
| break; | |||
| } | |||
| case COMPLIANCE_LINK_CHECK_REQ: | |||
| { | |||
| MlmeReq_t mlmeReq; | |||
| mlmeReq.Type = MLME_LINK_CHECK; | |||
| CompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, | |||
| mlmeReq.ReqReturn.DutyCycleWaitTime ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_DEVICE_TIME_REQ: | |||
| { | |||
| CompliancePackage.OnDeviceTimeRequest( ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_PING_SLOT_INFO_REQ: | |||
| { | |||
| ComplianceTestState.ClassBStatus.PingSlotPeriodicity = mcpsIndication->Buffer[cmdIndex++]; | |||
| ComplianceParams->OnPingSlotPeriodicityChanged( ComplianceTestState.ClassBStatus.PingSlotPeriodicity ); | |||
| break; | |||
| } | |||
| case COMPLIANCE_BEACON_CNT_REQ: | |||
| { | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_BEACON_CNT_ANS; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceTestState.ClassBStatus.BeaconCnt; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceTestState.ClassBStatus.BeaconCnt >> 8; | |||
| break; | |||
| } | |||
| case COMPLIANCE_BEACON_CNT_RESET_REQ: | |||
| { | |||
| ComplianceTestState.ClassBStatus.BeaconCnt = 0; | |||
| break; | |||
| } | |||
| case COMPLIANCE_TX_CW_REQ: | |||
| { | |||
| MlmeReq_t mlmeReq; | |||
| if( mcpsIndication->BufferSize == 7 ) | |||
| { | |||
| mlmeReq.Type = MLME_TXCW; | |||
| mlmeReq.Req.TxCw.Timeout = | |||
| ( uint16_t )( mcpsIndication->Buffer[cmdIndex] | ( mcpsIndication->Buffer[cmdIndex + 1] << 8 ) ); | |||
| cmdIndex += 2; | |||
| mlmeReq.Req.TxCw.Frequency = | |||
| ( uint32_t )( mcpsIndication->Buffer[cmdIndex] | ( mcpsIndication->Buffer[cmdIndex + 1] << 8 ) | | |||
| ( mcpsIndication->Buffer[cmdIndex + 2] << 16 ) ) * | |||
| 100; | |||
| cmdIndex += 3; | |||
| mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[cmdIndex++]; | |||
| CompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, | |||
| mlmeReq.ReqReturn.DutyCycleWaitTime ); | |||
| } | |||
| break; | |||
| } | |||
| case COMPLIANCE_DUT_FPORT_224_DISABLE_REQ: | |||
| { | |||
| mibReq.Type = MIB_IS_CERT_FPORT_ON; | |||
| mibReq.Param.IsCertPortOn = false; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| ComplianceTestState.IsResetCmdPending = true; | |||
| break; | |||
| } | |||
| case COMPLIANCE_DUT_VERSION_REQ: | |||
| { | |||
| Version_t lrwanVersion; | |||
| Version_t lrwanRpVersion; | |||
| MibRequestConfirm_t mibReq; | |||
| mibReq.Type = MIB_LORAWAN_VERSION; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| lrwanVersion = mibReq.Param.LrWanVersion.LoRaWan; | |||
| lrwanRpVersion = mibReq.Param.LrWanVersion.LoRaWanRegion; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_DUT_VERSION_ANS; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceParams->FwVersion.Fields.Major; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceParams->FwVersion.Fields.Minor; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceParams->FwVersion.Fields.Patch; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceParams->FwVersion.Fields.Revision; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanVersion.Fields.Major; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanVersion.Fields.Minor; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanVersion.Fields.Patch; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanVersion.Fields.Revision; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanRpVersion.Fields.Major; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanRpVersion.Fields.Minor; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanRpVersion.Fields.Patch; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = lrwanRpVersion.Fields.Revision; | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| if( ComplianceTestState.DataBufferSize != 0 ) | |||
| { | |||
| ComplianceTestState.IsTxPending = true; | |||
| } | |||
| else | |||
| { | |||
| // Abort any pending Tx as a new command has been processed | |||
| ComplianceTestState.IsTxPending = false; | |||
| } | |||
| } | |||
| static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm ) | |||
| { | |||
| switch( mlmeConfirm->MlmeRequest ) | |||
| { | |||
| case MLME_BEACON_ACQUISITION: | |||
| { | |||
| if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) | |||
| { | |||
| ClassBStatusReset( ); | |||
| ComplianceTestState.ClassBStatus.IsBeaconRxOn = true; | |||
| } | |||
| else | |||
| { | |||
| ComplianceTestState.ClassBStatus.IsBeaconRxOn = false; | |||
| } | |||
| SendBeaconRxStatusInd( ); | |||
| break; | |||
| } | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| static void LmhpComplianceOnMlmeIndication( MlmeIndication_t* mlmeIndication ) | |||
| { | |||
| if( ComplianceTestState.Initialized == false ) | |||
| { | |||
| return; | |||
| } | |||
| switch( mlmeIndication->MlmeIndication ) | |||
| { | |||
| case MLME_BEACON_LOST: | |||
| { | |||
| ClassBStatusReset( ); | |||
| SendBeaconRxStatusInd( ); | |||
| break; | |||
| } | |||
| case MLME_BEACON: | |||
| { | |||
| if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED ) | |||
| { | |||
| // As we received a beacon ensure that IsBeaconRxOn is set to true | |||
| if( ComplianceTestState.ClassBStatus.IsBeaconRxOn == false ) | |||
| { | |||
| ComplianceTestState.ClassBStatus.IsBeaconRxOn = true; | |||
| } | |||
| ComplianceTestState.ClassBStatus.BeaconCnt++; | |||
| } | |||
| ComplianceTestState.ClassBStatus.Info = mlmeIndication->BeaconInfo; | |||
| SendBeaconRxStatusInd( ); | |||
| break; | |||
| } | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| static void SendBeaconRxStatusInd( void ) | |||
| { | |||
| uint32_t frequency = ComplianceTestState.ClassBStatus.Info.Frequency / 100; | |||
| ComplianceTestState.DataBufferSize = 0; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = COMPLIANCE_BEACON_RX_STATUS_IND; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( ComplianceTestState.ClassBStatus.IsBeaconRxOn == true ) ? 1 : 0; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.BeaconCnt ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.BeaconCnt >> 8 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( frequency ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( frequency >> 8 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( frequency >> 16 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ComplianceTestState.ClassBStatus.Info.Datarate; | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Rssi ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Rssi >> 8 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Snr ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Param ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Time.Seconds ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Time.Seconds >> 8 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Time.Seconds >> 16 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.Time.Seconds >> 24 ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.InfoDesc ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[0] ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[1] ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[2] ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[3] ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[4] ); | |||
| ComplianceTestState.DataBuffer[ComplianceTestState.DataBufferSize++] = ( uint8_t )( ComplianceTestState.ClassBStatus.Info.GwSpecific.Info[5] ); | |||
| ComplianceTestState.IsTxPending = true; | |||
| } | |||
| @@ -0,0 +1,60 @@ | |||
| /*! | |||
| * \file LmhpCompliance.h | |||
| * | |||
| * \brief Implements the LoRa-Alliance certification protocol handling | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMHP_COMPLIANCE__ | |||
| #define __LMHP_COMPLIANCE__ | |||
| #include "LoRaMac.h" | |||
| #include "LmHandlerTypes.h" | |||
| #include "LmhPackage.h" | |||
| /*! | |||
| * Compliance package identifier. | |||
| * | |||
| * \remark This value must be unique amongst the packages | |||
| */ | |||
| #define PACKAGE_ID_COMPLIANCE 0 | |||
| /*! | |||
| * Compliance test protocol handler parameters | |||
| */ | |||
| typedef struct LmhpComplianceParams_s | |||
| { | |||
| /*! | |||
| * Current firmware version | |||
| */ | |||
| Version_t FwVersion; | |||
| /*! | |||
| * | |||
| */ | |||
| void ( *OnTxPeriodicityChanged )( uint32_t periodicity ); | |||
| /*! | |||
| * | |||
| */ | |||
| void ( *OnTxFrameCtrlChanged )( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| /*! | |||
| * | |||
| */ | |||
| void ( *OnPingSlotPeriodicityChanged )( uint8_t pingSlotPeriodicity ); | |||
| }LmhpComplianceParams_t; | |||
| LmhPackage_t *LmphCompliancePackageFactory( void ); | |||
| #endif // __LMHP_COMPLIANCE__ | |||
| @@ -0,0 +1,529 @@ | |||
| /*! | |||
| * \file LmhpFragmentation.c | |||
| * | |||
| * \brief Implements the LoRa-Alliance fragmented data block transport package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include "LmHandler.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "FragDecoder.h" | |||
| /*! | |||
| * LoRaWAN Application Layer Fragmented Data Block Transport Specification | |||
| */ | |||
| #define FRAGMENTATION_PORT 201 | |||
| #define FRAGMENTATION_ID 3 | |||
| #define FRAGMENTATION_VERSION 1 | |||
| #define FRAGMENTATION_MAX_SESSIONS 4 | |||
| // Fragmentation Tx delay state | |||
| typedef enum LmhpFragmentationTxDelayStates_e | |||
| { | |||
| // Tx delay in idle state. | |||
| FRAGMENTATION_TX_DELAY_STATE_IDLE, | |||
| // Tx delay to be started. | |||
| FRAGMENTATION_TX_DELAY_STATE_START, | |||
| // Tx delay to be stopped. | |||
| FRAGMENTATION_TX_DELAY_STATE_STOP, | |||
| }LmhpFragmentationTxDelayStates_t; | |||
| /*! | |||
| * Package current context | |||
| */ | |||
| typedef struct LmhpFragmentationState_s | |||
| { | |||
| bool Initialized; | |||
| bool IsTxPending; | |||
| LmhpFragmentationTxDelayStates_t TxDelayState; | |||
| uint8_t DataBufferMaxSize; | |||
| uint8_t *DataBuffer; | |||
| uint8_t *file; | |||
| }LmhpFragmentationState_t; | |||
| typedef enum LmhpFragmentationMoteCmd_e | |||
| { | |||
| FRAGMENTATION_PKG_VERSION_ANS = 0x00, | |||
| FRAGMENTATION_FRAG_STATUS_ANS = 0x01, | |||
| FRAGMENTATION_FRAG_SESSION_SETUP_ANS = 0x02, | |||
| FRAGMENTATION_FRAG_SESSION_DELETE_ANS = 0x03, | |||
| }LmhpFragmentationMoteCmd_t; | |||
| typedef enum LmhpFragmentationSrvCmd_e | |||
| { | |||
| FRAGMENTATION_PKG_VERSION_REQ = 0x00, | |||
| FRAGMENTATION_FRAG_STATUS_REQ = 0x01, | |||
| FRAGMENTATION_FRAG_SESSION_SETUP_REQ = 0x02, | |||
| FRAGMENTATION_FRAG_SESSION_DELETE_REQ = 0x03, | |||
| FRAGMENTATION_DATA_FRAGMENT = 0x08, | |||
| }LmhpFragmentationSrvCmd_t; | |||
| /*! | |||
| * LoRaWAN fragmented data block transport handler parameters | |||
| */ | |||
| static LmhpFragmentationParams_t* LmhpFragmentationParams; | |||
| /*! | |||
| * Initializes the package with provided parameters | |||
| * | |||
| * \param [IN] params Pointer to the package parameters | |||
| * \param [IN] dataBuffer Pointer to main application buffer | |||
| * \param [IN] dataBufferMaxSize Main application buffer maximum size | |||
| */ | |||
| static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); | |||
| /*! | |||
| * Returns the current package initialization status. | |||
| * | |||
| * \retval status Package initialization status | |||
| * [true: Initialized, false: Not initialized] | |||
| */ | |||
| static bool LmhpFragmentationIsInitialized( void ); | |||
| /*! | |||
| * Returns if a package transmission is pending or not. | |||
| * | |||
| * \retval status Package transmission status | |||
| * [true: pending, false: Not pending] | |||
| */ | |||
| static bool LmhpFragmentationIsTxPending( void ); | |||
| /*! | |||
| * Processes the internal package events. | |||
| */ | |||
| static void LmhpFragmentationProcess( void ); | |||
| /*! | |||
| * Processes the MCPS Indication | |||
| * | |||
| * \param [IN] mcpsIndication MCPS indication primitive data | |||
| */ | |||
| static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication ); | |||
| static LmhpFragmentationState_t LmhpFragmentationState = | |||
| { | |||
| .Initialized = false, | |||
| .IsTxPending = false, | |||
| .TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE, | |||
| }; | |||
| typedef struct FragGroupData_s | |||
| { | |||
| bool IsActive; | |||
| union | |||
| { | |||
| uint8_t Value; | |||
| struct | |||
| { | |||
| uint8_t McGroupBitMask: 4; | |||
| uint8_t FragIndex: 2; | |||
| uint8_t RFU: 2; | |||
| }Fields; | |||
| }FragSession; | |||
| uint16_t FragNb; | |||
| uint8_t FragSize; | |||
| union | |||
| { | |||
| uint8_t Value; | |||
| struct | |||
| { | |||
| uint8_t BlockAckDelay: 3; | |||
| uint8_t FragAlgo: 3; | |||
| uint8_t RFU: 2; | |||
| }Fields; | |||
| }Control; | |||
| uint8_t Padding; | |||
| uint32_t Descriptor; | |||
| }FragGroupData_t; | |||
| typedef struct FragSessionData_s | |||
| { | |||
| FragGroupData_t FragGroupData; | |||
| FragDecoderStatus_t FragDecoderStatus; | |||
| int32_t FragDecoderPorcessStatus; | |||
| }FragSessionData_t; | |||
| FragSessionData_t FragSessionData[FRAGMENTATION_MAX_SESSIONS]; | |||
| // Answer struct for the commands. | |||
| LmHandlerAppData_t DelayedReplyAppData; | |||
| static LmhPackage_t LmhpFragmentationPackage = | |||
| { | |||
| .Port = FRAGMENTATION_PORT, | |||
| .Init = LmhpFragmentationInit, | |||
| .IsInitialized = LmhpFragmentationIsInitialized, | |||
| .IsTxPending = LmhpFragmentationIsTxPending, | |||
| .Process = LmhpFragmentationProcess, | |||
| .OnMcpsConfirmProcess = NULL, // Not used in this package | |||
| .OnMcpsIndicationProcess = LmhpFragmentationOnMcpsIndication, | |||
| .OnMlmeConfirmProcess = NULL, // Not used in this package | |||
| .OnMlmeIndicationProcess = NULL, // Not used in this package | |||
| .OnMacMcpsRequest = NULL, // To be initialized by LmHandler | |||
| .OnMacMlmeRequest = NULL, // To be initialized by LmHandler | |||
| .OnJoinRequest = NULL, // To be initialized by LmHandler | |||
| .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler | |||
| .OnSysTimeUpdate = NULL, // To be initialized by LmHandler | |||
| }; | |||
| // Delay value. | |||
| static uint32_t TxDelayTime; | |||
| // Fragment Delay Timer struct | |||
| static TimerEvent_t FragmentTxDelayTimer; | |||
| /*! | |||
| * \brief Callback function for Fragment delay timer. | |||
| */ | |||
| static void OnFragmentTxDelay( void* context ) | |||
| { | |||
| // Stop the timer. | |||
| TimerStop( &FragmentTxDelayTimer ); | |||
| // Set the state. | |||
| LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_STOP; | |||
| } | |||
| LmhPackage_t *LmhpFragmentationPackageFactory( void ) | |||
| { | |||
| return &LmhpFragmentationPackage; | |||
| } | |||
| static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) | |||
| { | |||
| if( ( params != NULL ) && ( dataBuffer != NULL ) ) | |||
| { | |||
| LmhpFragmentationParams = ( LmhpFragmentationParams_t* )params; | |||
| LmhpFragmentationState.DataBuffer = dataBuffer; | |||
| LmhpFragmentationState.DataBufferMaxSize = dataBufferMaxSize; | |||
| LmhpFragmentationState.Initialized = true; | |||
| // Initialize Fragmentation delay time. | |||
| TxDelayTime = 0; | |||
| // Initialize Fragmentation delay timer. | |||
| TimerInit( &FragmentTxDelayTimer, OnFragmentTxDelay ); | |||
| } | |||
| else | |||
| { | |||
| LmhpFragmentationParams = NULL; | |||
| LmhpFragmentationState.Initialized = false; | |||
| } | |||
| LmhpFragmentationState.IsTxPending = false; | |||
| } | |||
| static bool LmhpFragmentationIsInitialized( void ) | |||
| { | |||
| return LmhpFragmentationState.Initialized; | |||
| } | |||
| static bool LmhpFragmentationIsTxPending( void ) | |||
| { | |||
| return LmhpFragmentationState.IsTxPending; | |||
| } | |||
| static void LmhpFragmentationProcess( void ) | |||
| { | |||
| LmhpFragmentationTxDelayStates_t delayTimerState; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| delayTimerState = LmhpFragmentationState.TxDelayState; | |||
| // Set the state to idle so that the other states are executed only when they are set | |||
| // in the appropriate functions. | |||
| LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE; | |||
| CRITICAL_SECTION_END( ); | |||
| switch( delayTimerState ) | |||
| { | |||
| case FRAGMENTATION_TX_DELAY_STATE_START: | |||
| // Set the timer with the initially calculated Delay value. | |||
| TimerSetValue( &FragmentTxDelayTimer, TxDelayTime ); | |||
| // Start the timer. | |||
| TimerStart( &FragmentTxDelayTimer ); | |||
| break; | |||
| case FRAGMENTATION_TX_DELAY_STATE_STOP: | |||
| // Send the reply. | |||
| LmHandlerSend( &DelayedReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| break; | |||
| case FRAGMENTATION_TX_DELAY_STATE_IDLE: | |||
| // Intentional fall through | |||
| default: | |||
| // Nothing to do. | |||
| break; | |||
| } | |||
| } | |||
| static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication ) | |||
| { | |||
| uint8_t cmdIndex = 0; | |||
| uint8_t dataBufferIndex = 0; | |||
| bool isAnswerDelayed = false; | |||
| // Answer struct for the commands. | |||
| LmHandlerAppData_t cmdReplyAppData; | |||
| // Co-efficient used to calculate delay. | |||
| uint8_t blockAckDelay = 0; | |||
| if( mcpsIndication->Port != FRAGMENTATION_PORT ) | |||
| { | |||
| return; | |||
| } | |||
| while( cmdIndex < mcpsIndication->BufferSize ) | |||
| { | |||
| switch( mcpsIndication->Buffer[cmdIndex++] ) | |||
| { | |||
| case FRAGMENTATION_PKG_VERSION_REQ: | |||
| { | |||
| if( mcpsIndication->Multicast == 1 ) | |||
| { | |||
| // Multicast channel. Don't process command. | |||
| break; | |||
| } | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_PKG_VERSION_ANS; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_ID; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_VERSION; | |||
| break; | |||
| } | |||
| case FRAGMENTATION_FRAG_STATUS_REQ: | |||
| { | |||
| uint8_t fragIndex = mcpsIndication->Buffer[cmdIndex++]; | |||
| uint8_t participants = fragIndex & 0x01; | |||
| fragIndex >>= 1; | |||
| FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( ); | |||
| if( ( participants == 1 ) || | |||
| ( ( participants == 0 ) && ( FragSessionData[fragIndex].FragDecoderStatus.FragNbLost > 0 ) ) ) | |||
| { | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_STATUS_ANS; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbRx & 0xFF; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = ( fragIndex << 6 ) | | |||
| ( ( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx >> 8 ) & 0x3F ); | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbLost; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.MatrixError & 0x01; | |||
| // Fetch the co-efficient value required to calculate delay of that respective session. | |||
| blockAckDelay = FragSessionData[fragIndex].FragGroupData.Control.Fields.BlockAckDelay; | |||
| isAnswerDelayed = true; | |||
| } | |||
| break; | |||
| } | |||
| case FRAGMENTATION_FRAG_SESSION_SETUP_REQ: | |||
| { | |||
| if( mcpsIndication->Multicast == 1 ) | |||
| { | |||
| // Multicast channel. Don't process command. | |||
| break; | |||
| } | |||
| FragSessionData_t fragSessionData; | |||
| uint8_t status = 0x00; | |||
| fragSessionData.FragGroupData.FragSession.Value = mcpsIndication->Buffer[cmdIndex++]; | |||
| fragSessionData.FragGroupData.FragNb = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF; | |||
| fragSessionData.FragGroupData.FragNb |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00; | |||
| fragSessionData.FragGroupData.FragSize = mcpsIndication->Buffer[cmdIndex++]; | |||
| fragSessionData.FragGroupData.Control.Value = mcpsIndication->Buffer[cmdIndex++]; | |||
| fragSessionData.FragGroupData.Padding = mcpsIndication->Buffer[cmdIndex++]; | |||
| fragSessionData.FragGroupData.Descriptor = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| if( fragSessionData.FragGroupData.Control.Fields.FragAlgo > 0 ) | |||
| { | |||
| status |= 0x01; // Encoding unsupported | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| if( ( fragSessionData.FragGroupData.FragNb > FRAG_MAX_NB ) || | |||
| ( fragSessionData.FragGroupData.FragSize > FRAG_MAX_SIZE ) || | |||
| ( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > FragDecoderGetMaxFileSize( ) ) ) | |||
| { | |||
| status |= 0x02; // Not enough Memory | |||
| } | |||
| #else | |||
| if( ( fragSessionData.FragGroupData.FragNb > FRAG_MAX_NB ) || | |||
| ( fragSessionData.FragGroupData.FragSize > FRAG_MAX_SIZE ) || | |||
| ( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > LmhpFragmentationParams->BufferSize ) ) | |||
| { | |||
| status |= 0x02; // Not enough Memory | |||
| } | |||
| #endif | |||
| status |= ( fragSessionData.FragGroupData.FragSession.Fields.FragIndex << 6 ) & 0xC0; | |||
| if( fragSessionData.FragGroupData.FragSession.Fields.FragIndex >= FRAGMENTATION_MAX_SESSIONS ) | |||
| { | |||
| status |= 0x04; // FragSession index not supported | |||
| } | |||
| // Descriptor is not really defined in the specification | |||
| // Not clear how to handle this. | |||
| // Currently the descriptor is always correct | |||
| if( fragSessionData.FragGroupData.Descriptor != 0x01020304 ) | |||
| { | |||
| //status |= 0x08; // Wrong Descriptor | |||
| } | |||
| if( ( status & 0x0F ) == 0 ) | |||
| { | |||
| // The FragSessionSetup is accepted | |||
| fragSessionData.FragGroupData.IsActive = true; | |||
| fragSessionData.FragDecoderPorcessStatus = FRAG_SESSION_ONGOING; | |||
| FragSessionData[fragSessionData.FragGroupData.FragSession.Fields.FragIndex] = fragSessionData; | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| FragDecoderInit( fragSessionData.FragGroupData.FragNb, | |||
| fragSessionData.FragGroupData.FragSize, | |||
| &LmhpFragmentationParams->DecoderCallbacks ); | |||
| #else | |||
| FragDecoderInit( fragSessionData.FragGroupData.FragNb, | |||
| fragSessionData.FragGroupData.FragSize, | |||
| LmhpFragmentationParams->Buffer, | |||
| LmhpFragmentationParams->BufferSize ); | |||
| #endif | |||
| } | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_SETUP_ANS; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status; | |||
| isAnswerDelayed = false; | |||
| break; | |||
| } | |||
| case FRAGMENTATION_FRAG_SESSION_DELETE_REQ: | |||
| { | |||
| if( mcpsIndication->Multicast == 1 ) | |||
| { | |||
| // Multicast channel. Don't process command. | |||
| break; | |||
| } | |||
| uint8_t status = 0x00; | |||
| uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; | |||
| status |= id; | |||
| if( ( id >= FRAGMENTATION_MAX_SESSIONS ) || ( FragSessionData[id].FragGroupData.IsActive == false ) ) | |||
| { | |||
| status |= 0x04; // Session does not exist | |||
| } | |||
| else | |||
| { | |||
| // Delete session | |||
| FragSessionData[id].FragGroupData.IsActive = false; | |||
| } | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_DELETE_ANS; | |||
| LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status; | |||
| isAnswerDelayed = false; | |||
| break; | |||
| } | |||
| case FRAGMENTATION_DATA_FRAGMENT: | |||
| { | |||
| uint8_t fragIndex = 0; | |||
| uint16_t fragCounter = 0; | |||
| fragCounter = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF; | |||
| fragCounter |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00; | |||
| fragIndex = ( fragCounter >> 14 ) & 0x03; | |||
| fragCounter &= 0x3FFF; | |||
| if( mcpsIndication->Multicast == 1 ) | |||
| { | |||
| // Message received on a multicast address | |||
| // | |||
| // TODO: Not working yet | |||
| // | |||
| // Check McGroupBitMask | |||
| //uint8_t groupId = LoRaMacMcChannelGetGroupId( mcpsIndication->DevAddress ); | |||
| //if( ( groupId == 0xFF ) || | |||
| // ( ( FragSessionData[fragIndex].FragGroupData.FragSession.Fields.McGroupBitMask & ( 1 << groupId ) ) == 0 ) ) | |||
| //{ | |||
| // // Ignore message | |||
| // break; | |||
| //} | |||
| } | |||
| if( FragSessionData[fragIndex].FragDecoderPorcessStatus == FRAG_SESSION_ONGOING ) | |||
| { | |||
| FragSessionData[fragIndex].FragDecoderPorcessStatus = FragDecoderProcess( fragCounter, &mcpsIndication->Buffer[cmdIndex] ); | |||
| FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( ); | |||
| if( LmhpFragmentationParams->OnProgress != NULL ) | |||
| { | |||
| LmhpFragmentationParams->OnProgress( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx, | |||
| FragSessionData[fragIndex].FragGroupData.FragNb, | |||
| FragSessionData[fragIndex].FragGroupData.FragSize, | |||
| FragSessionData[fragIndex].FragDecoderStatus.FragNbLost ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( FragSessionData[fragIndex].FragDecoderPorcessStatus >= 0 ) | |||
| { | |||
| // Fragmentation successfully done | |||
| FragSessionData[fragIndex].FragDecoderPorcessStatus = FRAG_SESSION_NOT_STARTED; | |||
| if( LmhpFragmentationParams->OnDone != NULL ) | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus, | |||
| ( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding ); | |||
| #else | |||
| LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus, | |||
| LmhpFragmentationParams->Buffer, | |||
| ( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding ); | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| cmdIndex += FragSessionData[fragIndex].FragGroupData.FragSize; | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| // After processing the commands, if the end-node has to reply back then a flag is checked if the | |||
| // reply is to be sent immediately or with a delay. | |||
| // In some scenarios it is not desired that multiple end-notes send uplinks at the same time to | |||
| // the same server. (Example: Fragment status during a multicast FUOTA) | |||
| if( dataBufferIndex != 0 ) | |||
| { | |||
| // Prepare Answer that is to be transmitted | |||
| cmdReplyAppData.Buffer = LmhpFragmentationState.DataBuffer; | |||
| cmdReplyAppData.BufferSize = dataBufferIndex; | |||
| cmdReplyAppData.Port = FRAGMENTATION_PORT; | |||
| if( isAnswerDelayed == true ) | |||
| { | |||
| // Delay value is calculated using BlockAckDelay which is communicated by server during the FragSessionSetupReq | |||
| // Pseudo Random Delay = rand(0:1) * 2^(blockAckDelay + 4) Seconds. | |||
| // Delay = Pseudo Random Delay * 1000 milli seconds. | |||
| // Eg: blockAckDelay = 7 | |||
| // Pseudo Random Delay = rand(0:1) * 2^11 | |||
| // rand(0:1) seconds = rand(0:1000) milliseconds | |||
| // Delay = rand(0:1000) * 2048 => 2048000ms = 34 minutes | |||
| TxDelayTime = randr( 0, 1000 ) * ( 1 << ( blockAckDelay + 4 ) ); | |||
| DelayedReplyAppData = cmdReplyAppData; | |||
| LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_START; | |||
| } | |||
| else | |||
| { | |||
| // Send the prepared answer | |||
| LmHandlerSend( &cmdReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| /*! | |||
| * \file LmhpFragmentation.h | |||
| * | |||
| * \brief Implements the LoRa-Alliance fragmented data block transport package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMHP_FRAGMENTATION_H__ | |||
| #define __LMHP_FRAGMENTATION_H__ | |||
| #include "LoRaMac.h" | |||
| #include "LmHandlerTypes.h" | |||
| #include "LmhPackage.h" | |||
| #include "FragDecoder.h" | |||
| /*! | |||
| * Fragmentation data block transport package identifier. | |||
| * | |||
| * \remark This value must be unique amongst the packages | |||
| */ | |||
| #define PACKAGE_ID_FRAGMENTATION 3 | |||
| /*! | |||
| * Fragmentation package parameters | |||
| */ | |||
| typedef struct LmhpFragmentationParams_s | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * FragDecoder Write/Read function callbacks | |||
| */ | |||
| FragDecoderCallbacks_t DecoderCallbacks; | |||
| #else | |||
| /*! | |||
| * Pointer to the un-fragmented received buffer. | |||
| */ | |||
| uint8_t *Buffer; | |||
| /*! | |||
| * Size of the un-fragmented received buffer. | |||
| */ | |||
| uint32_t BufferSize; | |||
| #endif | |||
| /*! | |||
| * Notifies the progress of the current fragmentation session | |||
| * | |||
| * \param [IN] fragCounter Fragment counter | |||
| * \param [IN] fragNb Number of fragments | |||
| * \param [IN] fragSize Size of fragments | |||
| * \param [IN] fragNbLost Number of lost fragments | |||
| */ | |||
| void ( *OnProgress )( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| /*! | |||
| * Notifies that the fragmentation session is finished | |||
| * | |||
| * \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING, | |||
| * FRAG_SESSION_FINISHED or | |||
| * FragDecoder.Status.FragNbLost] | |||
| * \param [IN] size Received file size | |||
| */ | |||
| void ( *OnDone )( int32_t status, uint32_t size ); | |||
| #else | |||
| /*! | |||
| * Notifies that the fragmentation session is finished | |||
| * | |||
| * \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING, | |||
| * FRAG_SESSION_FINISHED or | |||
| * FragDecoder.Status.FragNbLost] | |||
| * \param [IN] file Pointer to the reception file buffer | |||
| * \param [IN] size Received file size | |||
| */ | |||
| void ( *OnDone )( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| }LmhpFragmentationParams_t; | |||
| LmhPackage_t *LmhpFragmentationPackageFactory( void ); | |||
| #endif // __LMHP_FRAGMENTATION_H__ | |||
| @@ -0,0 +1,457 @@ | |||
| /*! | |||
| * \file LmhpRemoteMcastSetup.c | |||
| * | |||
| * \brief Implements the LoRa-Alliance remote multicast setup package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include "LmHandler.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #define DBG_TRACE 1 | |||
| #if DBG_TRACE == 1 | |||
| #include <stdio.h> | |||
| /*! | |||
| * Works in the same way as the printf function does. | |||
| */ | |||
| #define DBG( ... ) \ | |||
| do \ | |||
| { \ | |||
| printf( __VA_ARGS__ ); \ | |||
| }while( 0 ) | |||
| #else | |||
| #define DBG( ... ) | |||
| #endif | |||
| /*! | |||
| * LoRaWAN Application Layer Remote multicast setup Specification | |||
| */ | |||
| #define REMOTE_MCAST_SETUP_PORT 200 | |||
| #define REMOTE_MCAST_SETUP_ID 2 | |||
| #define REMOTE_MCAST_SETUP_VERSION 1 | |||
| typedef enum LmhpRemoteMcastSetupSessionStates_e | |||
| { | |||
| REMOTE_MCAST_SETUP_SESSION_STATE_IDLE, | |||
| REMOTE_MCAST_SETUP_SESSION_STATE_START, | |||
| REMOTE_MCAST_SETUP_SESSION_STATE_STOP, | |||
| }LmhpRemoteMcastSetupSessionStates_t; | |||
| /*! | |||
| * Package current context | |||
| */ | |||
| typedef struct LmhpRemoteMcastSetupState_s | |||
| { | |||
| bool Initialized; | |||
| bool IsTxPending; | |||
| LmhpRemoteMcastSetupSessionStates_t SessionState; | |||
| uint8_t DataBufferMaxSize; | |||
| uint8_t *DataBuffer; | |||
| }LmhpRemoteMcastSetupState_t; | |||
| typedef enum LmhpRemoteMcastSetupMoteCmd_e | |||
| { | |||
| REMOTE_MCAST_SETUP_PKG_VERSION_ANS = 0x00, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS = 0x01, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS = 0x02, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS = 0x03, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS = 0x04, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_ANS = 0x05, | |||
| }LmhpRemoteMcastSetupMoteCmd_t; | |||
| typedef enum LmhpRemoteMcastSetupSrvCmd_e | |||
| { | |||
| REMOTE_MCAST_SETUP_PKG_VERSION_REQ = 0x00, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ = 0x01, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ = 0x02, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ = 0x03, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ = 0x04, | |||
| REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ = 0x05, | |||
| }LmhpRemoteMcastSetupSrvCmd_t; | |||
| /*! | |||
| * Initializes the package with provided parameters | |||
| * | |||
| * \param [IN] params Pointer to the package parameters | |||
| * \param [IN] dataBuffer Pointer to main application buffer | |||
| * \param [IN] dataBufferMaxSize Main application buffer maximum size | |||
| */ | |||
| static void LmhpRemoteMcastSetupInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); | |||
| /*! | |||
| * Returns the current package initialization status. | |||
| * | |||
| * \retval status Package initialization status | |||
| * [true: Initialized, false: Not initialized] | |||
| */ | |||
| static bool LmhpRemoteMcastSetupIsInitialized( void ); | |||
| /*! | |||
| * Returns if a package transmission is pending or not. | |||
| * | |||
| * \retval status Package transmission status | |||
| * [true: pending, false: Not pending] | |||
| */ | |||
| static bool LmhpRemoteMcastSetupIsTxPending( void ); | |||
| /*! | |||
| * Processes the internal package events. | |||
| */ | |||
| static void LmhpRemoteMcastSetupProcess( void ); | |||
| /*! | |||
| * Processes the MCPS Indication | |||
| * | |||
| * \param [IN] mcpsIndication MCPS indication primitive data | |||
| */ | |||
| static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication ); | |||
| static void OnSessionStartTimer( void *context ); | |||
| static void OnSessionStopTimer( void *context ); | |||
| static LmhpRemoteMcastSetupState_t LmhpRemoteMcastSetupState = | |||
| { | |||
| .Initialized = false, | |||
| .IsTxPending = false, | |||
| .SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE, | |||
| }; | |||
| typedef struct McGroupData_s | |||
| { | |||
| union | |||
| { | |||
| uint8_t Value; | |||
| struct | |||
| { | |||
| uint8_t McGroupId: 2; | |||
| uint8_t RFU: 6; | |||
| }Fields; | |||
| }IdHeader; | |||
| uint32_t McAddr; | |||
| uint8_t McKeyEncrypted[16]; | |||
| uint32_t McFCountMin; | |||
| uint32_t McFCountMax; | |||
| }McGroupData_t; | |||
| typedef enum eSessionState | |||
| { | |||
| SESSION_STOPED, | |||
| SESSION_STARTED | |||
| }SessionState_t; | |||
| typedef struct McSessionData_s | |||
| { | |||
| McGroupData_t McGroupData; | |||
| SessionState_t SessionState; | |||
| uint32_t SessionTime; | |||
| uint8_t SessionTimeout; | |||
| McRxParams_t RxParams; | |||
| }McSessionData_t; | |||
| McSessionData_t McSessionData[LORAMAC_MAX_MC_CTX]; | |||
| /*! | |||
| * Session start timer | |||
| */ | |||
| static TimerEvent_t SessionStartTimer; | |||
| /*! | |||
| * Session start timer | |||
| */ | |||
| static TimerEvent_t SessionStopTimer; | |||
| static LmhPackage_t LmhpRemoteMcastSetupPackage = | |||
| { | |||
| .Port = REMOTE_MCAST_SETUP_PORT, | |||
| .Init = LmhpRemoteMcastSetupInit, | |||
| .IsInitialized = LmhpRemoteMcastSetupIsInitialized, | |||
| .IsTxPending = LmhpRemoteMcastSetupIsTxPending, | |||
| .Process = LmhpRemoteMcastSetupProcess, | |||
| .OnMcpsConfirmProcess = NULL, // Not used in this package | |||
| .OnMcpsIndicationProcess = LmhpRemoteMcastSetupOnMcpsIndication, | |||
| .OnMlmeConfirmProcess = NULL, // Not used in this package | |||
| .OnMlmeIndicationProcess = NULL, // Not used in this package | |||
| .OnMacMcpsRequest = NULL, // To be initialized by LmHandler | |||
| .OnMacMlmeRequest = NULL, // To be initialized by LmHandler | |||
| .OnJoinRequest = NULL, // To be initialized by LmHandler | |||
| .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler | |||
| .OnSysTimeUpdate = NULL, // To be initialized by LmHandler | |||
| }; | |||
| LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void ) | |||
| { | |||
| return &LmhpRemoteMcastSetupPackage; | |||
| } | |||
| static void LmhpRemoteMcastSetupInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) | |||
| { | |||
| if( dataBuffer != NULL ) | |||
| { | |||
| LmhpRemoteMcastSetupState.DataBuffer = dataBuffer; | |||
| LmhpRemoteMcastSetupState.DataBufferMaxSize = dataBufferMaxSize; | |||
| LmhpRemoteMcastSetupState.Initialized = true; | |||
| TimerInit( &SessionStartTimer, OnSessionStartTimer ); | |||
| TimerInit( &SessionStopTimer, OnSessionStopTimer ); | |||
| } | |||
| else | |||
| { | |||
| LmhpRemoteMcastSetupState.Initialized = false; | |||
| } | |||
| LmhpRemoteMcastSetupState.IsTxPending = false; | |||
| } | |||
| static bool LmhpRemoteMcastSetupIsInitialized( void ) | |||
| { | |||
| return LmhpRemoteMcastSetupState.Initialized; | |||
| } | |||
| static bool LmhpRemoteMcastSetupIsTxPending( void ) | |||
| { | |||
| return LmhpRemoteMcastSetupState.IsTxPending; | |||
| } | |||
| static void LmhpRemoteMcastSetupProcess( void ) | |||
| { | |||
| LmhpRemoteMcastSetupSessionStates_t state; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| state = LmhpRemoteMcastSetupState.SessionState; | |||
| LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE; | |||
| CRITICAL_SECTION_END( ); | |||
| switch( state ) | |||
| { | |||
| case REMOTE_MCAST_SETUP_SESSION_STATE_START: | |||
| // Switch to Class C | |||
| LmHandlerRequestClass( CLASS_C ); | |||
| TimerSetValue( &SessionStopTimer, ( 1 << McSessionData[0].SessionTimeout ) * 1000 ); | |||
| TimerStart( &SessionStopTimer ); | |||
| break; | |||
| case REMOTE_MCAST_SETUP_SESSION_STATE_STOP: | |||
| // Switch back to Class A | |||
| LmHandlerRequestClass( CLASS_A ); | |||
| break; | |||
| case REMOTE_MCAST_SETUP_SESSION_STATE_IDLE: | |||
| // Intentional fall through | |||
| default: | |||
| // Nothing to do. | |||
| break; | |||
| } | |||
| } | |||
| static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication ) | |||
| { | |||
| uint8_t cmdIndex = 0; | |||
| uint8_t dataBufferIndex = 0; | |||
| if( mcpsIndication->Port != REMOTE_MCAST_SETUP_PORT ) | |||
| { | |||
| return; | |||
| } | |||
| while( cmdIndex < mcpsIndication->BufferSize ) | |||
| { | |||
| switch( mcpsIndication->Buffer[cmdIndex++] ) | |||
| { | |||
| case REMOTE_MCAST_SETUP_PKG_VERSION_REQ: | |||
| { | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_PKG_VERSION_ANS; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_ID; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_VERSION; | |||
| break; | |||
| } | |||
| case REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ: | |||
| { | |||
| // TODO implement command prosessing and handling | |||
| break; | |||
| } | |||
| case REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ: | |||
| { | |||
| uint8_t id = mcpsIndication->Buffer[cmdIndex++]; | |||
| McSessionData[id].McGroupData.IdHeader.Value = id; | |||
| McSessionData[id].McGroupData.McAddr = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| for( int8_t i = 0; i < 16; i++ ) | |||
| { | |||
| McSessionData[id].McGroupData.McKeyEncrypted[i] = mcpsIndication->Buffer[cmdIndex++]; | |||
| } | |||
| McSessionData[id].McGroupData.McFCountMin = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| McSessionData[id].McGroupData.McFCountMax = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| McChannelParams_t channel = | |||
| { | |||
| .IsRemotelySetup = true, | |||
| .Class = CLASS_C, // Field not used for multicast channel setup. Must be initialized to something | |||
| .IsEnabled = true, | |||
| .GroupID = ( AddressIdentifier_t )McSessionData[id].McGroupData.IdHeader.Fields.McGroupId, | |||
| .Address = McSessionData[id].McGroupData.McAddr, | |||
| .McKeys.McKeyE = McSessionData[id].McGroupData.McKeyEncrypted, | |||
| .FCountMin = McSessionData[id].McGroupData.McFCountMin, | |||
| .FCountMax = McSessionData[id].McGroupData.McFCountMax, | |||
| .RxParams.ClassC = // Field not used for multicast channel setup. Must be initialized to something | |||
| { | |||
| .Frequency = 0, | |||
| .Datarate = 0 | |||
| } | |||
| }; | |||
| uint8_t idError = 0x01; // One bit value | |||
| if( LoRaMacMcChannelSetup( &channel ) == LORAMAC_STATUS_OK ) | |||
| { | |||
| idError = 0x00; | |||
| } | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( idError << 2 ) | McSessionData[id].McGroupData.IdHeader.Fields.McGroupId; | |||
| break; | |||
| } | |||
| case REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ: | |||
| { | |||
| uint8_t status = 0x00; | |||
| uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; | |||
| status = id; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS; | |||
| if( LoRaMacMcChannelDelete( ( AddressIdentifier_t )id ) != LORAMAC_STATUS_OK ) | |||
| { | |||
| status |= 0x04; // McGroupUndefined bit set | |||
| } | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; | |||
| break; | |||
| } | |||
| case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ: | |||
| { | |||
| uint8_t status = 0x00; | |||
| uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; | |||
| McSessionData[id].SessionTime = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; | |||
| // Add Unix to Gps epcoh offset. The system time is based on Unix time. | |||
| McSessionData[id].SessionTime += UNIX_GPS_EPOCH_OFFSET; | |||
| McSessionData[id].SessionTimeout = mcpsIndication->Buffer[cmdIndex++] & 0x0F; | |||
| McSessionData[id].RxParams.ClassC.Frequency = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; | |||
| McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; | |||
| McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; | |||
| McSessionData[id].RxParams.ClassC.Frequency *= 100; | |||
| McSessionData[id].RxParams.ClassC.Datarate = mcpsIndication->Buffer[cmdIndex++]; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS; | |||
| if( LoRaMacMcChannelSetupRxParams( ( AddressIdentifier_t )id, &McSessionData[id].RxParams, &status ) == LORAMAC_STATUS_OK ) | |||
| { | |||
| SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 }; | |||
| curTime = SysTimeGet( ); | |||
| int32_t timeToSessionStart = McSessionData[id].SessionTime - curTime.Seconds; | |||
| if( timeToSessionStart > 0 ) | |||
| { | |||
| // Start session start timer | |||
| TimerSetValue( &SessionStartTimer, timeToSessionStart * 1000 ); | |||
| TimerStart( &SessionStartTimer ); | |||
| DBG( "Time2SessionStart: %ld ms\n", timeToSessionStart * 1000 ); | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 0 ) & 0xFF; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 8 ) & 0xFF; | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 16 ) & 0xFF; | |||
| break; | |||
| } | |||
| else | |||
| { | |||
| // Session start time before current device time | |||
| status |= 0x10; | |||
| } | |||
| } | |||
| LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; | |||
| break; | |||
| } | |||
| case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ: | |||
| { | |||
| // TODO implement command prosessing and handling | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if( dataBufferIndex != 0 ) | |||
| { | |||
| // Answer commands | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = LmhpRemoteMcastSetupState.DataBuffer, | |||
| .BufferSize = dataBufferIndex, | |||
| .Port = REMOTE_MCAST_SETUP_PORT | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| DBG( "ID : %d\n", McSessionData[0].McGroupData.IdHeader.Fields.McGroupId ); | |||
| DBG( "McAddr : %08lX\n", McSessionData[0].McGroupData.McAddr ); | |||
| DBG( "McKey : %02X", McSessionData[0].McGroupData.McKeyEncrypted[0] ); | |||
| for( int i = 1; i < 16; i++ ) | |||
| { | |||
| DBG( "-%02X", McSessionData[0].McGroupData.McKeyEncrypted[i] ); | |||
| } | |||
| DBG( "\n" ); | |||
| DBG( "McFCountMin : %lu\n", McSessionData[0].McGroupData.McFCountMin ); | |||
| DBG( "McFCountMax : %lu\n", McSessionData[0].McGroupData.McFCountMax ); | |||
| DBG( "SessionTime : %lu\n", McSessionData[0].SessionTime ); | |||
| DBG( "SessionTimeT: %d\n", McSessionData[0].SessionTimeout ); | |||
| DBG( "Rx Freq : %lu\n", McSessionData[0].RxParams.ClassC.Frequency ); | |||
| DBG( "Rx DR : DR_%d\n", McSessionData[0].RxParams.ClassC.Datarate ); | |||
| } | |||
| } | |||
| static void OnSessionStartTimer( void *context ) | |||
| { | |||
| TimerStop( &SessionStartTimer ); | |||
| LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START; | |||
| } | |||
| static void OnSessionStopTimer( void *context ) | |||
| { | |||
| TimerStop( &SessionStopTimer ); | |||
| LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP; | |||
| } | |||
| @@ -0,0 +1,47 @@ | |||
| /*! | |||
| * \file LmhpRemoteMcastSetup.h | |||
| * | |||
| * \brief Implements the LoRa-Alliance remote multicast setup package | |||
| * Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMHP_REMOTE_MCAST_SETUP_H__ | |||
| #define __LMHP_REMOTE_MCAST_SETUP_H__ | |||
| #include "LoRaMac.h" | |||
| #include "LmHandlerTypes.h" | |||
| #include "LmhPackage.h" | |||
| /*! | |||
| * Remote multicast setup package identifier. | |||
| * | |||
| * \remark This value must be unique amongst the packages | |||
| */ | |||
| #define PACKAGE_ID_REMOTE_MCAST_SETUP 2 | |||
| /*! | |||
| * Remote multicast setup package parameters | |||
| * | |||
| * This package doesn't require parameters | |||
| */ | |||
| //typedef struct LmhpRemoteMcastSetupParams_s | |||
| //{ | |||
| //}LmhpRemoteMcastSetupParams_t; | |||
| LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void ); | |||
| #endif // __LMHP_REMOTE_MCAST_SETUP_H__ | |||
| @@ -0,0 +1,428 @@ | |||
| /*! | |||
| * \file LmHandlerMsgDisplay.h | |||
| * | |||
| * \brief Common set of functions to display default messages from | |||
| * LoRaMacHandler. | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2019 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #include <stdio.h> | |||
| #include "utilities.h" | |||
| #include "timer.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| /*! | |||
| * MAC status strings | |||
| */ | |||
| const char* MacStatusStrings[] = | |||
| { | |||
| "OK", // LORAMAC_STATUS_OK | |||
| "Busy", // LORAMAC_STATUS_BUSY | |||
| "Service unknown", // LORAMAC_STATUS_SERVICE_UNKNOWN | |||
| "Parameter invalid", // LORAMAC_STATUS_PARAMETER_INVALID | |||
| "Frequency invalid", // LORAMAC_STATUS_FREQUENCY_INVALID | |||
| "Datarate invalid", // LORAMAC_STATUS_DATARATE_INVALID | |||
| "Frequency or datarate invalid", // LORAMAC_STATUS_FREQ_AND_DR_INVALID | |||
| "No network joined", // LORAMAC_STATUS_NO_NETWORK_JOINED | |||
| "Length error", // LORAMAC_STATUS_LENGTH_ERROR | |||
| "Region not supported", // LORAMAC_STATUS_REGION_NOT_SUPPORTED | |||
| "Skipped APP data", // LORAMAC_STATUS_SKIPPED_APP_DATA | |||
| "Duty-cycle restricted", // LORAMAC_STATUS_DUTYCYCLE_RESTRICTED | |||
| "No channel found", // LORAMAC_STATUS_NO_CHANNEL_FOUND | |||
| "No free channel found", // LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND | |||
| "Busy beacon reserved time", // LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME | |||
| "Busy ping-slot window time", // LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME | |||
| "Busy uplink collision", // LORAMAC_STATUS_BUSY_UPLINK_COLLISION | |||
| "Crypto error", // LORAMAC_STATUS_CRYPTO_ERROR | |||
| "FCnt handler error", // LORAMAC_STATUS_FCNT_HANDLER_ERROR | |||
| "MAC command error", // LORAMAC_STATUS_MAC_COMMAD_ERROR | |||
| "ClassB error", // LORAMAC_STATUS_CLASS_B_ERROR | |||
| "Confirm queue error", // LORAMAC_STATUS_CONFIRM_QUEUE_ERROR | |||
| "Multicast group undefined", // LORAMAC_STATUS_MC_GROUP_UNDEFINED | |||
| "Unknown error", // LORAMAC_STATUS_ERROR | |||
| }; | |||
| /*! | |||
| * MAC event info status strings. | |||
| */ | |||
| const char* EventInfoStatusStrings[] = | |||
| { | |||
| "OK", // LORAMAC_EVENT_INFO_STATUS_OK | |||
| "Error", // LORAMAC_EVENT_INFO_STATUS_ERROR | |||
| "Tx timeout", // LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT | |||
| "Rx 1 timeout", // LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT | |||
| "Rx 2 timeout", // LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT | |||
| "Rx1 error", // LORAMAC_EVENT_INFO_STATUS_RX1_ERROR | |||
| "Rx2 error", // LORAMAC_EVENT_INFO_STATUS_RX2_ERROR | |||
| "Join failed", // LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL | |||
| "Downlink repeated", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED | |||
| "Tx DR payload size error", // LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR | |||
| "Address fail", // LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL | |||
| "MIC fail", // LORAMAC_EVENT_INFO_STATUS_MIC_FAIL | |||
| "Multicast fail", // LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL | |||
| "Beacon locked", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED | |||
| "Beacon lost", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOST | |||
| "Beacon not found" // LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND | |||
| }; | |||
| /*! | |||
| * Prints the provided buffer in HEX | |||
| * | |||
| * \param buffer Buffer to be printed | |||
| * \param size Buffer size to be printed | |||
| */ | |||
| void PrintHexBuffer( uint8_t *buffer, uint8_t size ) | |||
| { | |||
| uint8_t newline = 0; | |||
| for( uint8_t i = 0; i < size; i++ ) | |||
| { | |||
| if( newline != 0 ) | |||
| { | |||
| printf( "\n" ); | |||
| newline = 0; | |||
| } | |||
| printf( "%02X ", buffer[i] ); | |||
| if( ( ( i + 1 ) % 16 ) == 0 ) | |||
| { | |||
| newline = 1; | |||
| } | |||
| } | |||
| printf( "\n" ); | |||
| } | |||
| void DisplayNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| if( state == LORAMAC_HANDLER_NVM_STORE ) | |||
| { | |||
| printf( "\n###### ============ CTXS STORED ============ ######\n" ); | |||
| } | |||
| else | |||
| { | |||
| printf( "\n###### =========== CTXS RESTORED =========== ######\n" ); | |||
| } | |||
| printf( "Size : %i\n\n", size ); | |||
| } | |||
| void DisplayNetworkParametersUpdate( CommissioningParams_t *commissioningParams ) | |||
| { | |||
| printf( "DevEui : %02X", commissioningParams->DevEui[0] ); | |||
| for( int i = 1; i < 8; i++ ) | |||
| { | |||
| printf( "-%02X", commissioningParams->DevEui[i] ); | |||
| } | |||
| printf( "\n" ); | |||
| printf( "JoinEui : %02X", commissioningParams->JoinEui[0] ); | |||
| for( int i = 1; i < 8; i++ ) | |||
| { | |||
| printf( "-%02X", commissioningParams->JoinEui[i] ); | |||
| } | |||
| printf( "\n" ); | |||
| printf( "Pin : %02X", commissioningParams->SePin[0] ); | |||
| for( int i = 1; i < 4; i++ ) | |||
| { | |||
| printf( "-%02X", commissioningParams->SePin[i] ); | |||
| } | |||
| printf( "\n\n" ); | |||
| } | |||
| void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| switch( mcpsReq->Type ) | |||
| { | |||
| case MCPS_CONFIRMED: | |||
| { | |||
| printf( "\n###### =========== MCPS-Request ============ ######\n" ); | |||
| printf( "###### MCPS_CONFIRMED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| case MCPS_UNCONFIRMED: | |||
| { | |||
| printf( "\n###### =========== MCPS-Request ============ ######\n" ); | |||
| printf( "###### MCPS_UNCONFIRMED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| case MCPS_PROPRIETARY: | |||
| { | |||
| printf( "\n###### =========== MCPS-Request ============ ######\n" ); | |||
| printf( "###### MCPS_PROPRIETARY ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| printf( "\n###### =========== MCPS-Request ============ ######\n" ); | |||
| printf( "###### MCPS_ERROR ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| } | |||
| printf( "STATUS : %s\n", MacStatusStrings[status] ); | |||
| if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) | |||
| { | |||
| printf( "Next Tx in : %lu [ms]\n", nextTxIn ); | |||
| } | |||
| } | |||
| void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| switch( mlmeReq->Type ) | |||
| { | |||
| case MLME_JOIN: | |||
| { | |||
| printf( "\n###### =========== MLME-Request ============ ######\n" ); | |||
| printf( "###### MLME_JOIN ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| case MLME_LINK_CHECK: | |||
| { | |||
| printf( "\n###### =========== MLME-Request ============ ######\n" ); | |||
| printf( "###### MLME_LINK_CHECK ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| case MLME_DEVICE_TIME: | |||
| { | |||
| printf( "\n###### =========== MLME-Request ============ ######\n" ); | |||
| printf( "###### MLME_DEVICE_TIME ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| case MLME_TXCW: | |||
| { | |||
| printf( "\n###### =========== MLME-Request ============ ######\n" ); | |||
| printf( "###### MLME_TXCW ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| printf( "\n###### =========== MLME-Request ============ ######\n" ); | |||
| printf( "###### MLME_UNKNOWN ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| break; | |||
| } | |||
| } | |||
| printf( "STATUS : %s\n", MacStatusStrings[status] ); | |||
| if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) | |||
| { | |||
| printf( "Next Tx in : %lu [ms]\n", nextTxIn ); | |||
| } | |||
| } | |||
| void DisplayJoinRequestUpdate( LmHandlerJoinParams_t *params ) | |||
| { | |||
| if( params->CommissioningParams->IsOtaaActivation == true ) | |||
| { | |||
| if( params->Status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "###### =========== JOINED ============ ######\n" ); | |||
| printf( "\nOTAA\n\n" ); | |||
| printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr ); | |||
| printf( "\n\n" ); | |||
| printf( "DATA RATE : DR_%d\n\n", params->Datarate ); | |||
| } | |||
| } | |||
| #if ( OVER_THE_AIR_ACTIVATION == 0 ) | |||
| else | |||
| { | |||
| printf( "###### =========== JOINED ============ ######\n" ); | |||
| printf( "\nABP\n\n" ); | |||
| printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr ); | |||
| printf( "\n\n" ); | |||
| } | |||
| #endif | |||
| } | |||
| void DisplayTxUpdate( LmHandlerTxParams_t *params ) | |||
| { | |||
| MibRequestConfirm_t mibGet; | |||
| if( params->IsMcpsConfirm == 0 ) | |||
| { | |||
| printf( "\n###### =========== MLME-Confirm ============ ######\n" ); | |||
| printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); | |||
| return; | |||
| } | |||
| printf( "\n###### =========== MCPS-Confirm ============ ######\n" ); | |||
| printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); | |||
| printf( "\n###### ===== UPLINK FRAME %8lu ===== ######\n", params->UplinkCounter ); | |||
| printf( "\n" ); | |||
| printf( "CLASS : %c\n", "ABC"[LmHandlerGetCurrentClass( )] ); | |||
| printf( "\n" ); | |||
| printf( "TX PORT : %d\n", params->AppData.Port ); | |||
| if( params->AppData.BufferSize != 0 ) | |||
| { | |||
| printf( "TX DATA : " ); | |||
| if( params->MsgType == LORAMAC_HANDLER_CONFIRMED_MSG ) | |||
| { | |||
| printf( "CONFIRMED - %s\n", ( params->AckReceived != 0 ) ? "ACK" : "NACK" ); | |||
| } | |||
| else | |||
| { | |||
| printf( "UNCONFIRMED\n" ); | |||
| } | |||
| PrintHexBuffer( params->AppData.Buffer, params->AppData.BufferSize ); | |||
| } | |||
| printf( "\n" ); | |||
| printf( "DATA RATE : DR_%d\n", params->Datarate ); | |||
| mibGet.Type = MIB_CHANNELS; | |||
| if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) | |||
| { | |||
| printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[params->Channel].Frequency ); | |||
| } | |||
| printf( "TX POWER : %d\n", params->TxPower ); | |||
| mibGet.Type = MIB_CHANNELS_MASK; | |||
| if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) | |||
| { | |||
| printf("CHANNEL MASK: "); | |||
| switch( LmHandlerGetActiveRegion( ) ) | |||
| { | |||
| case LORAMAC_REGION_AS923: | |||
| case LORAMAC_REGION_CN779: | |||
| case LORAMAC_REGION_EU868: | |||
| case LORAMAC_REGION_IN865: | |||
| case LORAMAC_REGION_KR920: | |||
| case LORAMAC_REGION_EU433: | |||
| case LORAMAC_REGION_RU864: | |||
| { | |||
| printf( "%04X ", mibGet.Param.ChannelsMask[0] ); | |||
| break; | |||
| } | |||
| case LORAMAC_REGION_AU915: | |||
| case LORAMAC_REGION_CN470: | |||
| case LORAMAC_REGION_US915: | |||
| { | |||
| for( uint8_t i = 0; i < 5; i++) | |||
| { | |||
| printf( "%04X ", mibGet.Param.ChannelsMask[i] ); | |||
| } | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| printf( "\n###### ========= Unknown Region ============ ######" ); | |||
| break; | |||
| } | |||
| } | |||
| printf("\n"); | |||
| } | |||
| printf( "\n" ); | |||
| } | |||
| void DisplayRxUpdate( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params ) | |||
| { | |||
| const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" }; | |||
| if( params->IsMcpsIndication == 0 ) | |||
| { | |||
| printf( "\n###### ========== MLME-Indication ========== ######\n" ); | |||
| printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); | |||
| return; | |||
| } | |||
| printf( "\n###### ========== MCPS-Indication ========== ######\n" ); | |||
| printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); | |||
| printf( "\n###### ===== DOWNLINK FRAME %8lu ===== ######\n", params->DownlinkCounter ); | |||
| printf( "RX WINDOW : %s\n", slotStrings[params->RxSlot] ); | |||
| printf( "RX PORT : %d\n", appData->Port ); | |||
| if( appData->BufferSize != 0 ) | |||
| { | |||
| printf( "RX DATA : \n" ); | |||
| PrintHexBuffer( appData->Buffer, appData->BufferSize ); | |||
| } | |||
| printf( "\n" ); | |||
| printf( "DATA RATE : DR_%d\n", params->Datarate ); | |||
| printf( "RX RSSI : %d\n", params->Rssi ); | |||
| printf( "RX SNR : %d\n", params->Snr ); | |||
| printf( "\n" ); | |||
| } | |||
| void DisplayBeaconUpdate( LoRaMacHandlerBeaconParams_t *params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| default: | |||
| case LORAMAC_HANDLER_BEACON_ACQUIRING: | |||
| { | |||
| printf( "\n###### ========= BEACON ACQUIRING ========== ######\n" ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| { | |||
| printf( "\n###### ============ BEACON LOST ============ ######\n" ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| printf( "\n###### ===== BEACON %8lu ==== ######\n", params->Info.Time.Seconds ); | |||
| printf( "GW DESC : %d\n", params->Info.GwSpecific.InfoDesc ); | |||
| printf( "GW INFO : " ); | |||
| PrintHexBuffer( params->Info.GwSpecific.Info, 6 ); | |||
| printf( "\n" ); | |||
| printf( "FREQ : %lu\n", params->Info.Frequency ); | |||
| printf( "DATA RATE : DR_%d\n", params->Info.Datarate ); | |||
| printf( "RX RSSI : %d\n", params->Info.Rssi ); | |||
| printf( "RX SNR : %d\n", params->Info.Snr ); | |||
| printf( "\n" ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| printf( "\n###### ======== BEACON NOT RECEIVED ======== ######\n" ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| void DisplayClassUpdate( DeviceClass_t deviceClass ) | |||
| { | |||
| printf( "\n\n###### ===== Switch to Class %c done. ===== ######\n\n", "ABC"[deviceClass] ); | |||
| } | |||
| void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion ) | |||
| { | |||
| printf( "\n###### ===================================== ######\n\n" ); | |||
| printf( "Application name : %s\n", appName ); | |||
| printf( "Application version: %d.%d.%d\n", appVersion->Fields.Major, appVersion->Fields.Minor, appVersion->Fields.Patch ); | |||
| printf( "GitHub base version: %d.%d.%d\n", gitHubVersion->Fields.Major, gitHubVersion->Fields.Minor, gitHubVersion->Fields.Patch ); | |||
| printf( "\n###### ===================================== ######\n\n" ); | |||
| } | |||
| @@ -0,0 +1,104 @@ | |||
| /*! | |||
| * \file LmHandlerMsgDisplay.h | |||
| * | |||
| * \brief Common set of functions to display default messages from | |||
| * LoRaMacHandler. | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2019 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| #ifndef __LMHANDLER_MSG_DISPLAY_H__ | |||
| #define __LMHANDLER_MSG_DISPLAY_H__ | |||
| #include "utilities.h" | |||
| #include "LmHandler.h" | |||
| /*! | |||
| * \brief Displays NVM context operation state | |||
| * | |||
| * \param [IN] state Indicates if we are storing (true) or | |||
| * restoring (false) the NVM context | |||
| * | |||
| * \param [IN] size Number of data bytes which were stored or restored. | |||
| */ | |||
| void DisplayNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| /*! | |||
| * \brief Displays updated network parameters | |||
| * | |||
| * \param [IN] commissioningParams Commissioning provided parameters | |||
| */ | |||
| void DisplayNetworkParametersUpdate( CommissioningParams_t* commissioningParams ); | |||
| /*! | |||
| * \brief Displays updated McpsRequest | |||
| * | |||
| * \param [IN] status McpsRequest execution status | |||
| * \param [IN] mcpsReq McpsRequest command executed | |||
| * \param [IN] nextTxIn Time to wait for the next uplink transmission | |||
| */ | |||
| void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| /*! | |||
| * \brief Displays updated MlmeRequest | |||
| * | |||
| * \param [IN] status MlmeRequest execution status | |||
| * \param [IN] mlmeReq MlmeRequest command executed | |||
| * \param [IN] nextTxIn Time to wait for the next uplink transmission | |||
| */ | |||
| void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| /*! | |||
| * \brief Displays updated JoinRequest | |||
| * | |||
| * \param [IN] params Executed JoinRequest parameters | |||
| */ | |||
| void DisplayJoinRequestUpdate( LmHandlerJoinParams_t* params ); | |||
| /*! | |||
| * \brief Displays Tx params | |||
| * | |||
| * \param [IN] params Tx parameters | |||
| */ | |||
| void DisplayTxUpdate( LmHandlerTxParams_t* params ); | |||
| /*! | |||
| * \brief Displays Rx params | |||
| * | |||
| * \param [IN] appData Receive data payload and port number | |||
| * \param [IN] params Rx parameters | |||
| */ | |||
| void DisplayRxUpdate( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| /*! | |||
| * \brief Displays beacon status update | |||
| * | |||
| * \param [IN] params Beacon parameters | |||
| */ | |||
| void DisplayBeaconUpdate( LoRaMacHandlerBeaconParams_t* params ); | |||
| /*! | |||
| * \brief Displays end-device class update | |||
| * | |||
| * \param [IN] deviceClass Current end-device class | |||
| */ | |||
| void DisplayClassUpdate( DeviceClass_t deviceClass ); | |||
| /*! | |||
| * \brief Displays application information | |||
| */ | |||
| void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion ); | |||
| #endif // __LMHANDLER_MSG_DISPLAY_H__ | |||
| @@ -0,0 +1,272 @@ | |||
| /*! | |||
| * \file NvmDataMgmt.c | |||
| * | |||
| * \brief NVM context management implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| * embedded.connectivity.solutions=============== | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| * | |||
| * \author Daniel Jaeckle ( STACKFORCE ) | |||
| * | |||
| * \author Johannes Bruder ( STACKFORCE ) | |||
| */ | |||
| #include <stdio.h> | |||
| #include "utilities.h" | |||
| #include "nvmm.h" | |||
| #include "LoRaMac.h" | |||
| #include "NvmDataMgmt.h" | |||
| /*! | |||
| * Enables/Disables the context storage management storage. | |||
| * Must be enabled for LoRaWAN 1.0.4 or later. | |||
| */ | |||
| #ifndef CONTEXT_MANAGEMENT_ENABLED | |||
| #define CONTEXT_MANAGEMENT_ENABLED 1 | |||
| #endif | |||
| static uint16_t NvmNotifyFlags = 0; | |||
| void NvmDataMgmtEvent( uint16_t notifyFlags ) | |||
| { | |||
| NvmNotifyFlags = notifyFlags; | |||
| } | |||
| uint16_t NvmDataMgmtStore( void ) | |||
| { | |||
| #if( CONTEXT_MANAGEMENT_ENABLED == 1 ) | |||
| uint16_t offset = 0; | |||
| uint16_t dataSize = 0; | |||
| MibRequestConfirm_t mibReq; | |||
| mibReq.Type = MIB_NVM_CTXS; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| LoRaMacNvmData_t* nvm = mibReq.Param.Contexts; | |||
| // Input checks | |||
| if( NvmNotifyFlags == LORAMAC_NVM_NOTIFY_FLAG_NONE ) | |||
| { | |||
| // There was no update. | |||
| return 0; | |||
| } | |||
| if( LoRaMacStop( ) != LORAMAC_STATUS_OK ) | |||
| { | |||
| return 0; | |||
| } | |||
| // Crypto | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_CRYPTO ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_CRYPTO ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->Crypto, sizeof( nvm->Crypto ), | |||
| offset ); | |||
| } | |||
| offset += sizeof( nvm->Crypto ); | |||
| // MacGroup1 | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP1 ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP1 ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->MacGroup1, | |||
| sizeof( nvm->MacGroup1 ), offset ); | |||
| } | |||
| offset += sizeof( nvm->MacGroup1 ); | |||
| // MacGroup2 | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP2 ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP2 ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->MacGroup2, | |||
| sizeof( nvm->MacGroup2 ), offset ); | |||
| } | |||
| offset += sizeof( nvm->MacGroup2 ); | |||
| // Secure element | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_SECURE_ELEMENT ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_SECURE_ELEMENT ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->SecureElement, sizeof( nvm->SecureElement ), | |||
| offset ); | |||
| } | |||
| offset += sizeof( nvm->SecureElement ); | |||
| // Region group 1 | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP1 ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP1 ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->RegionGroup1, | |||
| sizeof( nvm->RegionGroup1 ), offset ); | |||
| } | |||
| offset += sizeof( nvm->RegionGroup1 ); | |||
| // Region group 2 | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP2 ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP2 ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->RegionGroup2, | |||
| sizeof( nvm->RegionGroup2 ), offset ); | |||
| } | |||
| offset += sizeof( nvm->RegionGroup2 ); | |||
| // Class b | |||
| if( ( NvmNotifyFlags & LORAMAC_NVM_NOTIFY_FLAG_CLASS_B ) == | |||
| LORAMAC_NVM_NOTIFY_FLAG_CLASS_B ) | |||
| { | |||
| dataSize += NvmmWrite( ( uint8_t* ) &nvm->ClassB, sizeof( nvm->ClassB ), | |||
| offset ); | |||
| } | |||
| offset += sizeof( nvm->ClassB ); | |||
| // Reset notification flags | |||
| NvmNotifyFlags = LORAMAC_NVM_NOTIFY_FLAG_NONE; | |||
| // Resume LoRaMac | |||
| LoRaMacStart( ); | |||
| return dataSize; | |||
| #else | |||
| return 0; | |||
| #endif | |||
| } | |||
| uint16_t NvmDataMgmtRestore( void ) | |||
| { | |||
| #if( CONTEXT_MANAGEMENT_ENABLED == 1 ) | |||
| MibRequestConfirm_t mibReq; | |||
| mibReq.Type = MIB_NVM_CTXS; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| LoRaMacNvmData_t* nvm = mibReq.Param.Contexts; | |||
| uint16_t offset = 0; | |||
| // Crypto | |||
| if( NvmmCrc32Check( sizeof( LoRaMacCryptoNvmData_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( LoRaMacCryptoNvmData_t ); | |||
| // Mac Group 1 | |||
| if( NvmmCrc32Check( sizeof( LoRaMacNvmDataGroup1_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( LoRaMacNvmDataGroup1_t ); | |||
| // Mac Group 2 | |||
| if( NvmmCrc32Check( sizeof( LoRaMacNvmDataGroup2_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( LoRaMacNvmDataGroup2_t ); | |||
| // Secure element | |||
| if( NvmmCrc32Check( sizeof( SecureElementNvmData_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( SecureElementNvmData_t ); | |||
| // Region group 1 | |||
| if( NvmmCrc32Check( sizeof( RegionNvmDataGroup1_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( RegionNvmDataGroup1_t ); | |||
| // Region group 2 | |||
| if( NvmmCrc32Check( sizeof( RegionNvmDataGroup2_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( RegionNvmDataGroup2_t ); | |||
| // Class b | |||
| if( NvmmCrc32Check( sizeof( LoRaMacClassBNvmData_t ), offset ) == false ) | |||
| { | |||
| return 0; | |||
| } | |||
| offset += sizeof( LoRaMacClassBNvmData_t ); | |||
| if( NvmmRead( ( uint8_t* ) nvm, sizeof( LoRaMacNvmData_t ), 0 ) == | |||
| sizeof( LoRaMacNvmData_t ) ) | |||
| { | |||
| return sizeof( LoRaMacNvmData_t ); | |||
| } | |||
| #endif | |||
| return 0; | |||
| } | |||
| bool NvmDataMgmtFactoryReset( void ) | |||
| { | |||
| uint16_t offset = 0; | |||
| #if( CONTEXT_MANAGEMENT_ENABLED == 1 ) | |||
| // Crypto | |||
| if( NvmmReset( sizeof( LoRaMacCryptoNvmData_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( LoRaMacCryptoNvmData_t ); | |||
| // Mac Group 1 | |||
| if( NvmmReset( sizeof( LoRaMacNvmDataGroup1_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( LoRaMacNvmDataGroup1_t ); | |||
| // Mac Group 2 | |||
| if( NvmmReset( sizeof( LoRaMacNvmDataGroup2_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( LoRaMacNvmDataGroup2_t ); | |||
| // Secure element | |||
| if( NvmmReset( sizeof( SecureElementNvmData_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( SecureElementNvmData_t ); | |||
| // Region group 1 | |||
| if( NvmmReset( sizeof( RegionNvmDataGroup1_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( RegionNvmDataGroup1_t ); | |||
| // Region group 2 | |||
| if( NvmmReset( sizeof( RegionNvmDataGroup2_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( RegionNvmDataGroup2_t ); | |||
| // Class b | |||
| if( NvmmReset( sizeof( LoRaMacClassBNvmData_t ), offset ) == false ) | |||
| { | |||
| return false; | |||
| } | |||
| offset += sizeof( LoRaMacClassBNvmData_t ); | |||
| #endif | |||
| return true; | |||
| } | |||
| @@ -0,0 +1,71 @@ | |||
| /*! | |||
| * \file NvmDataMgmt.h | |||
| * | |||
| * \brief NVM context management implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| * embedded.connectivity.solutions=============== | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| * | |||
| * \author Daniel Jaeckle ( STACKFORCE ) | |||
| * | |||
| * \author Johannes Bruder ( STACKFORCE ) | |||
| * | |||
| * \defgroup NVMDATAMGMT NVM context management implementation | |||
| * This module implements the NVM context handling | |||
| * \{ | |||
| */ | |||
| #ifndef __NVMDATAMGMT_H__ | |||
| #define __NVMDATAMGMT_H__ | |||
| /*! | |||
| * \brief NVM Management event. | |||
| * | |||
| * \param [IN] notifyFlags Bitmap which contains the information about modules that | |||
| * changed. | |||
| */ | |||
| void NvmDataMgmtEvent( uint16_t notifyFlags ); | |||
| /*! | |||
| * \brief Function which stores the MAC data into NVM, if required. | |||
| * | |||
| * \retval Number of bytes which were stored. | |||
| */ | |||
| uint16_t NvmDataMgmtStore( void ); | |||
| /*! | |||
| * \brief Function which restores the MAC data from NVM, if required. | |||
| * | |||
| * \retval Number of bytes which were restored. | |||
| */ | |||
| uint16_t NvmDataMgmtRestore(void ); | |||
| /*! | |||
| * \brief Resets the NVM data. | |||
| * | |||
| * \retval Returns true, if successful. | |||
| */ | |||
| bool NvmDataMgmtFactoryReset( void ); | |||
| /* \} */ | |||
| #endif // __NVMDATAMGMT_H__ | |||
| @@ -0,0 +1,56 @@ | |||
| /*! | |||
| * \file cli.h | |||
| * | |||
| * \brief Command Line Interface handling implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #include "NvmDataMgmt.h" | |||
| #include "cli.h" | |||
| void CliProcess( Uart_t* uart ) | |||
| { | |||
| uint8_t data = 0; | |||
| if( UartGetChar( uart, &data ) == 0 ) | |||
| { | |||
| if( data == '\x1B' ) | |||
| { // Escape character has been received | |||
| printf( "ESC + " ); | |||
| while( UartGetChar( uart, &data ) != 0 ) | |||
| { | |||
| } | |||
| printf( "%c\n", data ); | |||
| if( data == 'N' ) | |||
| { // N character has been received | |||
| data = 0; | |||
| // Reset NVM | |||
| if( NvmDataMgmtFactoryReset( ) == true ) | |||
| { | |||
| printf( "\n\nNVM factory reset succeed\n" ); | |||
| } | |||
| else | |||
| { | |||
| printf( "\n\nNVM factory reset failed\n" ); | |||
| } | |||
| printf( "\n\nPLEASE RESET THE END-DEVICE\n\n" ); | |||
| while( 1 ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| /*! | |||
| * \file cli.h | |||
| * | |||
| * \brief Command Line Interface handling definition | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #ifndef CLI_H | |||
| #define CLI_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #include "uart.h" | |||
| /*! | |||
| * Process characters received on the serial interface | |||
| * \remark Characters sequence 'ESC' + 'N' execute a NVM factory reset | |||
| * All other sequences are ignored | |||
| * | |||
| * \param [IN] uart UART interface object used by the command line interface | |||
| */ | |||
| void CliProcess( Uart_t* uart ); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // CLI_H | |||
| @@ -0,0 +1,33 @@ | |||
| /*! | |||
| * \file githubVersion.h | |||
| * | |||
| * \brief GitHub version definition | |||
| * | |||
| * \copyright Revised BSD License, see file LICENSE.txt | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2019-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #ifndef __GITHUB_VERSION_H__ | |||
| #define __GITHUB_VERSION_H__ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #define GITHUB_VERSION 0x04050000 // 4.5.0.0 | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // __GITHUB_VERSION_H__ | |||
| @@ -0,0 +1,746 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/B-L072Z-LRWAN1/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED3 | |||
| */ | |||
| static TimerEvent_t Led3Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| static void OnLed3TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // Rx | |||
| extern Gpio_t Led4; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &Led3Timer, OnLed3TimerEvent ); | |||
| TimerSetValue( &Led3Timer, 100 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 3 ON | |||
| GpioWrite( &Led3, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 3 OFF for each received downlink | |||
| GpioWrite( &Led3, 0 ); | |||
| TimerStart( &Led3Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 3 OFF | |||
| GpioWrite( &Led3, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 3 OFF | |||
| GpioWrite( &Led3, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| static void OnLed3TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led3Timer ); | |||
| // Switch LED 3 ON | |||
| GpioWrite( &Led3, 1 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,725 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/NAMote72/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board-config.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "gps.h" | |||
| #include "mpl3115.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = MPL3115ReadTemperature, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,721 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/NucleoL073/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,721 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/NucleoL152/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,721 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/NucleoL476/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,666 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/SAMR34/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 100 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 50 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Tick the RTC to execute callback in context of the main loop (in stead of the IRQ) | |||
| TimerProcess( ); | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 1 OFF for each received downlink | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| } | |||
| @@ -0,0 +1,697 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/SKiM880B/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| @@ -0,0 +1,697 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/SKiM881AXL/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| @@ -0,0 +1,697 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief FUOTA interop tests - test 01 | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file fuota-test-01/SKiM980A/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "LmhpClockSync.h" | |||
| #include "LmhpRemoteMcastSetup.h" | |||
| #include "LmhpFragmentation.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 40s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 40000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 5s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 5000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_3 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ); | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ); | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ); | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Defines the maximum size for the buffer receiving the fragmentation result. | |||
| * | |||
| * \remark By default FragDecoder.h defines: | |||
| * \ref FRAG_MAX_NB 21 | |||
| * \ref FRAG_MAX_SIZE 50 | |||
| * | |||
| * FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE | |||
| * | |||
| * If bigger file size is to be received or is fragmented differently | |||
| * one must update those parameters. | |||
| */ | |||
| #define UNFRAGMENTED_DATA_SIZE ( 21 * 50 ) | |||
| /* | |||
| * Un-fragmented data storage. | |||
| */ | |||
| static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE]; | |||
| static LmhpFragmentationParams_t FragmentationParams = | |||
| { | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| .DecoderCallbacks = | |||
| { | |||
| .FragDecoderWrite = FragDecoderWrite, | |||
| .FragDecoderRead = FragDecoderRead, | |||
| }, | |||
| #else | |||
| .Buffer = UnfragmentedData, | |||
| .BufferSize = UNFRAGMENTED_DATA_SIZE, | |||
| #endif | |||
| .OnProgress = OnFragProgress, | |||
| .OnDone = OnFragDone | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /* | |||
| * Indicates if the system time has been synchronized | |||
| */ | |||
| static volatile bool IsClockSynched = false; | |||
| /* | |||
| * MC Session Started | |||
| */ | |||
| static volatile bool IsMcSessionStarted = false; | |||
| /* | |||
| * Indicates if the file transfer is done | |||
| */ | |||
| static volatile bool IsFileTransferDone = false; | |||
| /* | |||
| * Received file computed CRC32 | |||
| */ | |||
| static volatile uint32_t FileRxCrc = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 100 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "fuota-test-01", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL ); | |||
| LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams ); | |||
| IsClockSynched = false; | |||
| IsFileTransferDone = false; | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| switch( deviceClass ) | |||
| { | |||
| default: | |||
| case CLASS_A: | |||
| { | |||
| IsMcSessionStarted = false; | |||
| break; | |||
| } | |||
| case CLASS_B: | |||
| { | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| IsMcSessionStarted = true; | |||
| break; | |||
| } | |||
| case CLASS_C: | |||
| { | |||
| IsMcSessionStarted = true; | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| IsClockSynched = isSynchronized; | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| IsClockSynched = true; | |||
| } | |||
| #endif | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| UnfragmentedData[addr + i] = data[i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size ) | |||
| { | |||
| if( size >= UNFRAGMENTED_DATA_SIZE ) | |||
| { | |||
| return -1; // Fail | |||
| } | |||
| for(uint32_t i = 0; i < size; i++ ) | |||
| { | |||
| data[i] = UnfragmentedData[addr + i]; | |||
| } | |||
| return 0; // Success | |||
| } | |||
| #endif | |||
| static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ) | |||
| { | |||
| // Switch LED 2 OFF for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### PROGRESS ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "RECEIVED : %5d / %5d Fragments\n", fragCounter, fragNb ); | |||
| printf( " %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize ); | |||
| printf( "LOST : %7d Fragments\n\n", fragNbLost ); | |||
| } | |||
| #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) | |||
| static void OnFragDone( int32_t status, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( UnfragmentedData, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #else | |||
| static void OnFragDone( int32_t status, uint8_t *file, uint32_t size ) | |||
| { | |||
| FileRxCrc = Crc32( file, size ); | |||
| IsFileTransferDone = true; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| printf( "\n###### =========== FRAG_DECODER ============ ######\n" ); | |||
| printf( "###### FINISHED ######\n"); | |||
| printf( "###### ===================================== ######\n"); | |||
| printf( "STATUS : %ld\n", status ); | |||
| printf( "CRC : %08lX\n\n", FileRxCrc ); | |||
| } | |||
| #endif | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| if( IsMcSessionStarted == false ) | |||
| { | |||
| if( IsFileTransferDone == false ) | |||
| { | |||
| if( IsClockSynched == false ) | |||
| { | |||
| status = LmhpClockSyncAppTimeReq( ); | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = randr( 0, 255 ); | |||
| // Send random packet | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 1, | |||
| .Port = 1, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq | |||
| AppDataBuffer[1] = FileRxCrc & 0x000000FF; | |||
| AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF; | |||
| AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF; | |||
| AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF; | |||
| // Send FragAuthReq | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 5, | |||
| .Port = 201, | |||
| }; | |||
| status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed ); | |||
| } | |||
| if( status == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| /*! | |||
| * \file firmwareVersion.h | |||
| * | |||
| * \brief Firmware version definition | |||
| * | |||
| * \copyright Revised BSD License, see file LICENSE.txt | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2019-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #ifndef __FIRMWARE_VERSION_H__ | |||
| #define __FIRMWARE_VERSION_H__ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #define FIRMWARE_VERSION 0x01020000 // 1.2.0.0 | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // __FIRMWARE_VERSION_H__ | |||
| @@ -0,0 +1,597 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/B-L072Z-LRWAN1/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED3 | |||
| */ | |||
| static TimerEvent_t Led3Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| static void OnLed3TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // Rx | |||
| extern Gpio_t Led4; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &Led3Timer, OnLed3TimerEvent ); | |||
| TimerSetValue( &Led3Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| GpioWrite( &Led4, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led3, 1 ); | |||
| TimerStart( &Led3Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| static void OnLed3TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led3Timer ); | |||
| // Switch LED 3 OFF | |||
| GpioWrite( &Led3, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,616 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/NAMote72/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board-config.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "gps.h" | |||
| #include "mpl3115.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = MPL3115ReadTemperature, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx and blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| GpioWrite( &Led3, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| #if defined( REGION_US915 ) | |||
| MibRequestConfirm_t mibReq; | |||
| if( BoardGetBatteryVoltage( ) < LOW_BAT_THRESHOLD ) | |||
| { | |||
| mibReq.Type = MIB_CHANNELS_TX_POWER; | |||
| LoRaMacMibGetRequestConfirm( &mibReq ); | |||
| // 30 dBm = TX_POWER_0, 28 dBm = TX_POWER_1, ..., 20 dBm = TX_POWER_5, ..., 10 dBm = TX_POWER_10 | |||
| // The if condition is then "less than" to check if the power is greater than 20 dBm | |||
| if( mibReq.Param.ChannelsTxPower < TX_POWER_5 ) | |||
| { | |||
| mibReq.Param.ChannelsTxPower = TX_POWER_5; | |||
| LoRaMacMibSetRequestConfirm( &mibReq ); | |||
| } | |||
| } | |||
| #endif | |||
| static uint8_t TxGpsData = 1; // GPS data transmission control | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| if( TxGpsData == 0 ) | |||
| { | |||
| CayenneLppAddDigitalInput( 0, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( 1, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppAddTemperature( 2, MPL3115ReadTemperature( ) ); | |||
| CayenneLppAddBarometricPressure( 3, MPL3115ReadPressure( ) / 100 ); | |||
| } | |||
| else | |||
| { | |||
| if( GpsHasFix( ) == true ) | |||
| { | |||
| double latitude = 0, longitude = 0; | |||
| uint16_t altitudeGps = 0xFFFF; | |||
| GpsGetLatestGpsPositionDouble( &latitude, &longitude ); | |||
| altitudeGps = GpsGetLatestGpsAltitude( ); // in m | |||
| CayenneLppAddGps( 4, latitude, longitude, altitudeGps ); | |||
| } | |||
| else | |||
| { | |||
| CayenneLppAddGps( 4, 0, 0, 0 ); | |||
| } | |||
| } | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| TxGpsData = ( TxGpsData + 1 ) & 0x01; // Send GPS data every 2 uplinks | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,571 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/NucleoL073/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,571 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/NucleoL152/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,571 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/NucleoL476/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| extern Gpio_t Led2; // Rx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart2; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart2 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,573 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/SAMR34/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 2 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED1 | |||
| */ | |||
| static TimerEvent_t Led1Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; // Tx | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 50 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Tick the RTC to execute callback in context of the main loop (in stead of the IRQ) | |||
| TimerProcess( ); | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 1 ON for each received downlink | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 1 Timeout event | |||
| */ | |||
| static void OnLed1TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led1Timer ); | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led1, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,586 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/SKiM880B/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 3 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx and blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| GpioWrite( &Led3, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| uint8_t potiPercentage = 0; | |||
| uint16_t vdd = 0; | |||
| // Read the current potentiometer setting in percent | |||
| potiPercentage = BoardGetPotiLevel( ); | |||
| // Read the current voltage level | |||
| BoardGetBatteryLevel( ); // Updates the value returned by BoardGetBatteryVoltage( ) function. | |||
| vdd = BoardGetBatteryVoltage( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppAddAnalogInput( channel++, potiPercentage ); | |||
| CayenneLppAddAnalogInput( channel++, vdd ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 4 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,586 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/SKiM881AXL/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 3 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx and blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| GpioWrite( &Led3, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| uint8_t potiPercentage = 0; | |||
| uint16_t vdd = 0; | |||
| // Read the current potentiometer setting in percent | |||
| potiPercentage = BoardGetPotiLevel( ); | |||
| // Read the current voltage level | |||
| BoardGetBatteryLevel( ); // Updates the value returned by BoardGetBatteryVoltage( ) function. | |||
| vdd = BoardGetBatteryVoltage( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppAddAnalogInput( channel++, potiPercentage ); | |||
| CayenneLppAddAnalogInput( channel++, vdd ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 4 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,586 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Performs a periodic uplink | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2018 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| */ | |||
| /*! \file periodic-uplink/SKiM980A/main.c */ | |||
| #include <stdio.h> | |||
| #include "../firmwareVersion.h" | |||
| #include "../../common/githubVersion.h" | |||
| #include "utilities.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "uart.h" | |||
| #include "RegionCommon.h" | |||
| #include "cli.h" | |||
| #include "Commissioning.h" | |||
| #include "LmHandler.h" | |||
| #include "LmhpCompliance.h" | |||
| #include "CayenneLpp.h" | |||
| #include "LmHandlerMsgDisplay.h" | |||
| #ifndef ACTIVE_REGION | |||
| #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." | |||
| #define ACTIVE_REGION LORAMAC_REGION_EU868 | |||
| #endif | |||
| /*! | |||
| * LoRaWAN default end-device class | |||
| */ | |||
| #define LORAWAN_DEFAULT_CLASS CLASS_A | |||
| /*! | |||
| * Defines the application data transmission duty cycle. 5s, value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE 5000 | |||
| /*! | |||
| * Defines a random delay for application data transmission duty cycle. 1s, | |||
| * value in [ms]. | |||
| */ | |||
| #define APP_TX_DUTYCYCLE_RND 1000 | |||
| /*! | |||
| * LoRaWAN Adaptive Data Rate | |||
| * | |||
| * \remark Please note that when ADR is enabled the end-device should be static | |||
| */ | |||
| #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON | |||
| /*! | |||
| * Default datarate | |||
| * | |||
| * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled | |||
| */ | |||
| #define LORAWAN_DEFAULT_DATARATE DR_0 | |||
| /*! | |||
| * LoRaWAN confirmed messages | |||
| */ | |||
| #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG | |||
| /*! | |||
| * User application data buffer size | |||
| */ | |||
| #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 | |||
| /*! | |||
| * LoRaWAN ETSI duty cycle control enable/disable | |||
| * | |||
| * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes | |||
| */ | |||
| #define LORAWAN_DUTYCYCLE_ON true | |||
| /*! | |||
| * LoRaWAN application port | |||
| * @remark The allowed port range is from 1 up to 223. Other values are reserved. | |||
| */ | |||
| #define LORAWAN_APP_PORT 3 | |||
| /*! | |||
| * | |||
| */ | |||
| typedef enum | |||
| { | |||
| LORAMAC_HANDLER_TX_ON_TIMER, | |||
| LORAMAC_HANDLER_TX_ON_EVENT, | |||
| }LmHandlerTxEvents_t; | |||
| /*! | |||
| * User application data | |||
| */ | |||
| static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; | |||
| /*! | |||
| * User application data structure | |||
| */ | |||
| static LmHandlerAppData_t AppData = | |||
| { | |||
| .Buffer = AppDataBuffer, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| /*! | |||
| * Specifies the state of the application LED | |||
| */ | |||
| static bool AppLedStateOn = false; | |||
| /*! | |||
| * Timer to handle the application data transmission duty cycle | |||
| */ | |||
| static TimerEvent_t TxTimer; | |||
| /*! | |||
| * Timer to handle the state of LED4 | |||
| */ | |||
| static TimerEvent_t Led4Timer; | |||
| /*! | |||
| * Timer to handle the state of LED2 | |||
| */ | |||
| static TimerEvent_t Led2Timer; | |||
| /*! | |||
| * Timer to handle the state of LED beacon indicator | |||
| */ | |||
| static TimerEvent_t LedBeaconTimer; | |||
| static void OnMacProcessNotify( void ); | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ); | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ); | |||
| static void OnTxData( LmHandlerTxParams_t* params ); | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); | |||
| static void OnClassChange( DeviceClass_t deviceClass ); | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); | |||
| #else | |||
| static void OnSysTimeUpdate( void ); | |||
| #endif | |||
| static void PrepareTxFrame( void ); | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ); | |||
| static void UplinkProcess( void ); | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ); | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ); | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ); | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ); | |||
| static LmHandlerCallbacks_t LmHandlerCallbacks = | |||
| { | |||
| .GetBatteryLevel = BoardGetBatteryLevel, | |||
| .GetTemperature = NULL, | |||
| .GetRandomSeed = BoardGetRandomSeed, | |||
| .OnMacProcess = OnMacProcessNotify, | |||
| .OnNvmDataChange = OnNvmDataChange, | |||
| .OnNetworkParametersChange = OnNetworkParametersChange, | |||
| .OnMacMcpsRequest = OnMacMcpsRequest, | |||
| .OnMacMlmeRequest = OnMacMlmeRequest, | |||
| .OnJoinRequest = OnJoinRequest, | |||
| .OnTxData = OnTxData, | |||
| .OnRxData = OnRxData, | |||
| .OnClassChange= OnClassChange, | |||
| .OnBeaconStatusChange = OnBeaconStatusChange, | |||
| .OnSysTimeUpdate = OnSysTimeUpdate, | |||
| }; | |||
| static LmHandlerParams_t LmHandlerParams = | |||
| { | |||
| .Region = ACTIVE_REGION, | |||
| .AdrEnable = LORAWAN_ADR_STATE, | |||
| .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, | |||
| .TxDatarate = LORAWAN_DEFAULT_DATARATE, | |||
| .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, | |||
| .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, | |||
| .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, | |||
| .DataBuffer = AppDataBuffer, | |||
| .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, | |||
| }; | |||
| static LmhpComplianceParams_t LmhpComplianceParams = | |||
| { | |||
| .FwVersion.Value = FIRMWARE_VERSION, | |||
| .OnTxPeriodicityChanged = OnTxPeriodicityChanged, | |||
| .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, | |||
| .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, | |||
| }; | |||
| /*! | |||
| * Indicates if LoRaMacProcess call is pending. | |||
| * | |||
| * \warning If variable is equal to 0 then the MCU can be set in low power mode | |||
| */ | |||
| static volatile uint8_t IsMacProcessPending = 0; | |||
| static volatile uint8_t IsTxFramePending = 0; | |||
| static volatile uint32_t TxPeriodicity = 0; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; // Tx | |||
| extern Gpio_t Led2; // Rx and blinks every 5 seconds when beacon is acquired | |||
| extern Gpio_t Led3; // App | |||
| /*! | |||
| * UART object used for command line interface handling | |||
| */ | |||
| extern Uart_t Uart1; | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led4Timer, OnLed4TimerEvent ); | |||
| TimerSetValue( &Led4Timer, 25 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 25 ); | |||
| TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); | |||
| TimerSetValue( &LedBeaconTimer, 5000 ); | |||
| // Initialize transmission periodicity variable | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| const Version_t appVersion = { .Value = FIRMWARE_VERSION }; | |||
| const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; | |||
| DisplayAppInfo( "periodic-uplink-lpp", | |||
| &appVersion, | |||
| &gitHubVersion ); | |||
| if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| printf( "LoRaMac wasn't properly initialized\n" ); | |||
| // Fatal error, endless loop. | |||
| while ( 1 ) | |||
| { | |||
| } | |||
| } | |||
| // Set system maximum tolerated rx error in milliseconds | |||
| LmHandlerSetSystemMaxRxError( 20 ); | |||
| // The LoRa-Alliance Compliance protocol package should always be | |||
| // initialized and activated. | |||
| LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); | |||
| LmHandlerJoin( ); | |||
| StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); | |||
| while( 1 ) | |||
| { | |||
| // Process characters sent over the command line interface | |||
| CliProcess( &Uart1 ); | |||
| // Processes the LoRaMac events | |||
| LmHandlerProcess( ); | |||
| // Process application uplinks management | |||
| UplinkProcess( ); | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| if( IsMacProcessPending == 1 ) | |||
| { | |||
| // Clear flag and prevent MCU to go into low power modes. | |||
| IsMacProcessPending = 0; | |||
| } | |||
| else | |||
| { | |||
| // The MCU wakes up through events | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| CRITICAL_SECTION_END( ); | |||
| } | |||
| } | |||
| static void OnMacProcessNotify( void ) | |||
| { | |||
| IsMacProcessPending = 1; | |||
| } | |||
| static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) | |||
| { | |||
| DisplayNvmDataChange( state, size ); | |||
| } | |||
| static void OnNetworkParametersChange( CommissioningParams_t* params ) | |||
| { | |||
| DisplayNetworkParametersUpdate( params ); | |||
| } | |||
| static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); | |||
| } | |||
| static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) | |||
| { | |||
| DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); | |||
| } | |||
| static void OnJoinRequest( LmHandlerJoinParams_t* params ) | |||
| { | |||
| DisplayJoinRequestUpdate( params ); | |||
| if( params->Status == LORAMAC_HANDLER_ERROR ) | |||
| { | |||
| LmHandlerJoin( ); | |||
| } | |||
| else | |||
| { | |||
| LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); | |||
| } | |||
| } | |||
| static void OnTxData( LmHandlerTxParams_t* params ) | |||
| { | |||
| DisplayTxUpdate( params ); | |||
| } | |||
| static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) | |||
| { | |||
| DisplayRxUpdate( appData, params ); | |||
| switch( appData->Port ) | |||
| { | |||
| case 1: // The application LED can be controlled on port 1 or 2 | |||
| case LORAWAN_APP_PORT: | |||
| { | |||
| AppLedStateOn = appData->Buffer[0] & 0x01; | |||
| GpioWrite( &Led3, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| // Switch LED 2 ON for each received downlink | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| static void OnClassChange( DeviceClass_t deviceClass ) | |||
| { | |||
| DisplayClassUpdate( deviceClass ); | |||
| // Inform the server as soon as possible that the end-device has switched to ClassB | |||
| LmHandlerAppData_t appData = | |||
| { | |||
| .Buffer = NULL, | |||
| .BufferSize = 0, | |||
| .Port = 0, | |||
| }; | |||
| LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); | |||
| } | |||
| static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) | |||
| { | |||
| switch( params->State ) | |||
| { | |||
| case LORAMAC_HANDLER_BEACON_RX: | |||
| { | |||
| TimerStart( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| case LORAMAC_HANDLER_BEACON_LOST: | |||
| case LORAMAC_HANDLER_BEACON_NRX: | |||
| { | |||
| TimerStop( &LedBeaconTimer ); | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| DisplayBeaconUpdate( params ); | |||
| } | |||
| #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) | |||
| static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) | |||
| { | |||
| } | |||
| #else | |||
| static void OnSysTimeUpdate( void ) | |||
| { | |||
| } | |||
| #endif | |||
| /*! | |||
| * Prepares the payload of the frame and transmits it. | |||
| */ | |||
| static void PrepareTxFrame( void ) | |||
| { | |||
| if( LmHandlerIsBusy( ) == true ) | |||
| { | |||
| return; | |||
| } | |||
| uint8_t channel = 0; | |||
| AppData.Port = LORAWAN_APP_PORT; | |||
| CayenneLppReset( ); | |||
| uint8_t potiPercentage = 0; | |||
| uint16_t vdd = 0; | |||
| // Read the current potentiometer setting in percent | |||
| potiPercentage = BoardGetPotiLevel( ); | |||
| // Read the current voltage level | |||
| BoardGetBatteryLevel( ); // Updates the value returned by BoardGetBatteryVoltage( ) function. | |||
| vdd = BoardGetBatteryVoltage( ); | |||
| CayenneLppAddDigitalInput( channel++, AppLedStateOn ); | |||
| CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); | |||
| CayenneLppAddAnalogInput( channel++, potiPercentage ); | |||
| CayenneLppAddAnalogInput( channel++, vdd ); | |||
| CayenneLppCopy( AppData.Buffer ); | |||
| AppData.BufferSize = CayenneLppGetSize( ); | |||
| if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) | |||
| { | |||
| // Switch LED 4 ON | |||
| GpioWrite( &Led4, 1 ); | |||
| TimerStart( &Led4Timer ); | |||
| } | |||
| } | |||
| static void StartTxProcess( LmHandlerTxEvents_t txEvent ) | |||
| { | |||
| switch( txEvent ) | |||
| { | |||
| default: | |||
| // Intentional fall through | |||
| case LORAMAC_HANDLER_TX_ON_TIMER: | |||
| { | |||
| // Schedule 1st packet transmission | |||
| TimerInit( &TxTimer, OnTxTimerEvent ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| OnTxTimerEvent( NULL ); | |||
| } | |||
| break; | |||
| case LORAMAC_HANDLER_TX_ON_EVENT: | |||
| { | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static void UplinkProcess( void ) | |||
| { | |||
| uint8_t isPending = 0; | |||
| CRITICAL_SECTION_BEGIN( ); | |||
| isPending = IsTxFramePending; | |||
| IsTxFramePending = 0; | |||
| CRITICAL_SECTION_END( ); | |||
| if( isPending == 1 ) | |||
| { | |||
| PrepareTxFrame( ); | |||
| } | |||
| } | |||
| static void OnTxPeriodicityChanged( uint32_t periodicity ) | |||
| { | |||
| TxPeriodicity = periodicity; | |||
| if( TxPeriodicity == 0 ) | |||
| { // Revert to application default periodicity | |||
| TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); | |||
| } | |||
| // Update timer periodicity | |||
| TimerStop( &TxTimer ); | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) | |||
| { | |||
| LmHandlerParams.IsTxConfirmed = isTxConfirmed; | |||
| } | |||
| static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) | |||
| { | |||
| LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; | |||
| } | |||
| /*! | |||
| * Function executed on TxTimer event | |||
| */ | |||
| static void OnTxTimerEvent( void* context ) | |||
| { | |||
| TimerStop( &TxTimer ); | |||
| IsTxFramePending = 1; | |||
| // Schedule next transmission | |||
| TimerSetValue( &TxTimer, TxPeriodicity ); | |||
| TimerStart( &TxTimer ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 4 Timeout event | |||
| */ | |||
| static void OnLed4TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led4Timer ); | |||
| // Switch LED 4 OFF | |||
| GpioWrite( &Led4, 0 ); | |||
| } | |||
| /*! | |||
| * Function executed on Led 2 Timeout event | |||
| */ | |||
| static void OnLed2TimerEvent( void* context ) | |||
| { | |||
| TimerStop( &Led2Timer ); | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 0 ); | |||
| } | |||
| /*! | |||
| * \brief Function executed on Beacon timer Timeout event | |||
| */ | |||
| static void OnLedBeaconTimerEvent( void* context ) | |||
| { | |||
| GpioWrite( &Led2, 1 ); | |||
| TimerStart( &Led2Timer ); | |||
| TimerStart( &LedBeaconTimer ); | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| /*! | |||
| * \file firmwareVersion.h | |||
| * | |||
| * \brief Firmware version definition | |||
| * | |||
| * \copyright Revised BSD License, see file LICENSE.txt | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2019-2020 Semtech | |||
| * | |||
| * \endcode | |||
| */ | |||
| #ifndef __FIRMWARE_VERSION_H__ | |||
| #define __FIRMWARE_VERSION_H__ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #define FIRMWARE_VERSION 0x01020000 // 1.2.0.0 | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // __FIRMWARE_VERSION_H__ | |||
| @@ -0,0 +1,369 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioWrite( &Led2, 1 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioWrite( &Led2, GpioRead( &Led2 ) ^ 1 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(ping-pong) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Allow selection of region | |||
| option(REGION_EU868 "Region EU868" ON) | |||
| option(REGION_US915 "Region US915" OFF) | |||
| option(REGION_CN779 "Region CN779" OFF) | |||
| option(REGION_EU433 "Region EU433" OFF) | |||
| option(REGION_AU915 "Region AU915" OFF) | |||
| option(REGION_AS923 "Region AS923" OFF) | |||
| option(REGION_CN470 "Region CN470" OFF) | |||
| option(REGION_KR920 "Region KR920" OFF) | |||
| option(REGION_IN865 "Region IN865" OFF) | |||
| option(REGION_RU864 "Region RU864" OFF) | |||
| set(REGION_LIST REGION_EU868 REGION_US915 REGION_CN779 REGION_EU433 REGION_AU915 REGION_AS923 REGION_CN470 REGION_KR920 REGION_IN865 REGION_RU864) | |||
| # Allow switching of modulation | |||
| set(MODULATION_LIST LORA FSK) | |||
| set(MODULATION LORA CACHE STRING "Default modulation is LoRa") | |||
| set_property(CACHE MODULATION PROPERTY STRINGS ${MODEM_LIST}) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Target | |||
| #--------------------------------------------------------------------------------------- | |||
| file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/${BOARD}/*.c") | |||
| add_executable(${PROJECT_NAME} | |||
| ${${PROJECT_NAME}_SOURCES} | |||
| $<TARGET_OBJECTS:system> | |||
| $<TARGET_OBJECTS:radio> | |||
| $<TARGET_OBJECTS:peripherals> | |||
| $<TARGET_OBJECTS:${BOARD}> | |||
| ) | |||
| # Loops through all regions and add compile time definitions for the enabled ones. | |||
| foreach( REGION ${REGION_LIST} ) | |||
| if(${REGION}) | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC -D"${REGION}") | |||
| endif() | |||
| endforeach() | |||
| if(MODULATION STREQUAL LORA) | |||
| target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MODEM_LORA) | |||
| elseif(MODULATION STREQUAL FSK) | |||
| target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MODEM_FSK) | |||
| endif() | |||
| # Add compile time definition for the mbed shield if set. | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC -D${MBED_RADIO_SHIELD}) | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:mac,INTERFACE_COMPILE_DEFINITIONS>> | |||
| ) | |||
| target_include_directories(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:system,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:radio,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:peripherals,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:${BOARD},INTERFACE_INCLUDE_DIRECTORIES>> | |||
| ) | |||
| set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) | |||
| target_link_libraries(${PROJECT_NAME} m) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Debugging and Binutils | |||
| #--------------------------------------------------------------------------------------- | |||
| include(gdb-helper) | |||
| include(binutils-arm-none-eabi) | |||
| # Generate debugger configurations | |||
| generate_run_gdb_stlink(${PROJECT_NAME}) | |||
| generate_run_gdb_openocd(${PROJECT_NAME}) | |||
| generate_vscode_launch_openocd(${PROJECT_NAME}) | |||
| # Print section sizes of target | |||
| print_section_sizes(${PROJECT_NAME}) | |||
| # Create output in hex and binary format | |||
| create_bin_output(${PROJECT_NAME}) | |||
| create_hex_output(${PROJECT_NAME}) | |||
| @@ -0,0 +1,362 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board-config.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioWrite( &Led2, 1 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioWrite( &Led2, GpioRead( &Led2 ) ^ 1 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,373 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led2 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led2 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,373 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led2 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led2 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,373 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led2 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led2 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,371 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| * | |||
| * \author Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017 | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| // Tick the RTC to execute callback in context of the main loop (in stead of the IRQ) | |||
| TimerProcess( ); | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioWrite( &Led1, GpioRead( &Led1 ) ^ 1 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,361 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led3; | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led4 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led3 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led4 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led3 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,361 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led3; | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led4 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led3 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led4 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led3 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,361 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Ping-Pong implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include <string.h> | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "delay.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 14 // dBm | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_FDEV 25000 // Hz | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| typedef enum | |||
| { | |||
| LOWPOWER, | |||
| RX, | |||
| RX_TIMEOUT, | |||
| RX_ERROR, | |||
| TX, | |||
| TX_TIMEOUT, | |||
| }States_t; | |||
| #define RX_TIMEOUT_VALUE 1000 | |||
| #define BUFFER_SIZE 64 // Define the payload size here | |||
| const uint8_t PingMsg[] = "PING"; | |||
| const uint8_t PongMsg[] = "PONG"; | |||
| uint16_t BufferSize = BUFFER_SIZE; | |||
| uint8_t Buffer[BUFFER_SIZE]; | |||
| States_t State = LOWPOWER; | |||
| int8_t RssiValue = 0; | |||
| int8_t SnrValue = 0; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led3; | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Tx Done event | |||
| */ | |||
| void OnTxDone( void ); | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnTxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Timeout event | |||
| */ | |||
| void OnRxTimeout( void ); | |||
| /*! | |||
| * \brief Function executed on Radio Rx Error event | |||
| */ | |||
| void OnRxError( void ); | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| bool isMaster = true; | |||
| uint8_t i; | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.TxDone = OnTxDone; | |||
| RadioEvents.RxDone = OnRxDone; | |||
| RadioEvents.TxTimeout = OnTxTimeout; | |||
| RadioEvents.RxTimeout = OnRxTimeout; | |||
| RadioEvents.RxError = OnRxError; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, | |||
| LORA_SPREADING_FACTOR, LORA_CODINGRATE, | |||
| LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, | |||
| FSK_DATARATE, 0, | |||
| FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, | |||
| true, 0, 0, 0, 3000 ); | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0,false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| while( 1 ) | |||
| { | |||
| switch( State ) | |||
| { | |||
| case RX: | |||
| if( isMaster == true ) | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PONG | |||
| GpioToggle( &Led4 ); | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { // A master already exists then become a slave | |||
| isMaster = false; | |||
| GpioToggle( &Led3 ); // Set LED off | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| else // valid reception but neither a PING or a PONG message | |||
| { // Set device as master ans start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( BufferSize > 0 ) | |||
| { | |||
| if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 ) | |||
| { | |||
| // Indicates on a LED that the received frame is a PING | |||
| GpioToggle( &Led4 ); | |||
| // Send the reply to the PONG string | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'O'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| // We fill the buffer with numbers for the payload | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else // valid reception but not a PING as expected | |||
| { // Set device as master and start again | |||
| isMaster = true; | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| } | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX: | |||
| // Indicates on a LED that we have sent a PING [Master] | |||
| // Indicates on a LED that we have sent a PONG [Slave] | |||
| GpioToggle( &Led3 ); | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case RX_TIMEOUT: | |||
| case RX_ERROR: | |||
| if( isMaster == true ) | |||
| { | |||
| // Send the next PING frame | |||
| Buffer[0] = 'P'; | |||
| Buffer[1] = 'I'; | |||
| Buffer[2] = 'N'; | |||
| Buffer[3] = 'G'; | |||
| for( i = 4; i < BufferSize; i++ ) | |||
| { | |||
| Buffer[i] = i - 4; | |||
| } | |||
| DelayMs( 1 ); | |||
| Radio.Send( Buffer, BufferSize ); | |||
| } | |||
| else | |||
| { | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| } | |||
| State = LOWPOWER; | |||
| break; | |||
| case TX_TIMEOUT: | |||
| Radio.Rx( RX_TIMEOUT_VALUE ); | |||
| State = LOWPOWER; | |||
| break; | |||
| case LOWPOWER: | |||
| default: | |||
| // Set low power | |||
| break; | |||
| } | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnTxDone( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX; | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| Radio.Sleep( ); | |||
| BufferSize = size; | |||
| memcpy( Buffer, payload, BufferSize ); | |||
| RssiValue = rssi; | |||
| SnrValue = snr; | |||
| State = RX; | |||
| } | |||
| void OnTxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = TX_TIMEOUT; | |||
| } | |||
| void OnRxTimeout( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_TIMEOUT; | |||
| } | |||
| void OnRxError( void ) | |||
| { | |||
| Radio.Sleep( ); | |||
| State = RX_ERROR; | |||
| } | |||
| @@ -0,0 +1,172 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(rx-sensi) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Allow selection of region | |||
| option(REGION_EU868 "Region EU868" ON) | |||
| option(REGION_US915 "Region US915" OFF) | |||
| option(REGION_CN779 "Region CN779" OFF) | |||
| option(REGION_EU433 "Region EU433" OFF) | |||
| option(REGION_AU915 "Region AU915" OFF) | |||
| option(REGION_AS923 "Region AS923" OFF) | |||
| option(REGION_CN470 "Region CN470" OFF) | |||
| option(REGION_KR920 "Region KR920" OFF) | |||
| option(REGION_IN865 "Region IN865" OFF) | |||
| option(REGION_RU864 "Region RU864" OFF) | |||
| set(REGION_LIST REGION_EU868 REGION_US915 REGION_CN779 REGION_EU433 REGION_AU915 REGION_AS923 REGION_CN470 REGION_KR920 REGION_IN865 REGION_RU864) | |||
| # Allow switching of modulation | |||
| set(MODULATION_LIST LORA FSK) | |||
| set(MODULATION LORA CACHE STRING "Default modulation is LoRa") | |||
| set_property(CACHE MODULATION PROPERTY STRINGS ${MODEM_LIST}) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Target | |||
| #--------------------------------------------------------------------------------------- | |||
| file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/${BOARD}/*.c") | |||
| add_executable(${PROJECT_NAME} | |||
| ${${PROJECT_NAME}_SOURCES} | |||
| $<TARGET_OBJECTS:system> | |||
| $<TARGET_OBJECTS:radio> | |||
| $<TARGET_OBJECTS:peripherals> | |||
| $<TARGET_OBJECTS:${BOARD}> | |||
| ) | |||
| # Loops through all regions and add compile time definitions for the enabled ones. | |||
| foreach( REGION ${REGION_LIST} ) | |||
| if(${REGION}) | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC -D"${REGION}") | |||
| endif() | |||
| endforeach() | |||
| if(MODULATION STREQUAL LORA) | |||
| target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MODEM_LORA) | |||
| elseif(MODULATION STREQUAL FSK) | |||
| target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MODEM_FSK) | |||
| endif() | |||
| # Add compile time definition for the mbed shield if set. | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC -D${MBED_RADIO_SHIELD}) | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:mac,INTERFACE_COMPILE_DEFINITIONS>> | |||
| ) | |||
| target_include_directories(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:system,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:radio,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:peripherals,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:${BOARD},INTERFACE_INCLUDE_DIRECTORIES>> | |||
| ) | |||
| set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) | |||
| target_link_libraries(${PROJECT_NAME} m) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Debugging and Binutils | |||
| #--------------------------------------------------------------------------------------- | |||
| include(gdb-helper) | |||
| include(binutils-arm-none-eabi) | |||
| # Generate debugger configurations | |||
| generate_run_gdb_stlink(${PROJECT_NAME}) | |||
| generate_run_gdb_openocd(${PROJECT_NAME}) | |||
| generate_vscode_launch_openocd(${PROJECT_NAME}) | |||
| # Print section sizes of target | |||
| print_section_sizes(${PROJECT_NAME}) | |||
| # Create output in hex and binary format | |||
| create_bin_output(${PROJECT_NAME}) | |||
| create_hex_output(${PROJECT_NAME}) | |||
| @@ -0,0 +1,165 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board-config.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,177 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,177 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,177 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,177 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| * | |||
| * \author Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017 | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| // Tick the RTC to execute callback in context of the main loop (in stead of the IRQ) | |||
| TimerProcess( ); | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 1 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led1, ledState ); | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 4 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led4, ledState ); | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 4 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led4, ledState ); | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Radio sensitivity test | |||
| * | |||
| * \remark When LED1 stops blinking LoRa packets aren't received any more and | |||
| * the sensitivity level has been reached. | |||
| * By reading the RF generator output power we can estimate the board | |||
| * sensitivity | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #if defined( USE_MODEM_LORA ) | |||
| #define LORA_BANDWIDTH 0 // [0: 125 kHz, | |||
| // 1: 250 kHz, | |||
| // 2: 500 kHz, | |||
| // 3: Reserved] | |||
| #define LORA_SPREADING_FACTOR 10 // [SF7..SF12] | |||
| #define LORA_CODINGRATE 1 // [1: 4/5, | |||
| // 2: 4/6, | |||
| // 3: 4/7, | |||
| // 4: 4/8] | |||
| #define LORA_SYMBOL_TIMEOUT 5 // Symbols | |||
| #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx | |||
| #define LORA_FIX_LENGTH_PAYLOAD_ON false | |||
| #define LORA_IQ_INVERSION_ON false | |||
| #elif defined( USE_MODEM_FSK ) | |||
| #define FSK_DATARATE 50000 // bps | |||
| #define FSK_BANDWIDTH 50000 // Hz | |||
| #define FSK_AFC_BANDWIDTH 83333 // Hz | |||
| #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx | |||
| #define FSK_FIX_LENGTH_PAYLOAD_ON false | |||
| #else | |||
| #error "Please define a modem in the compiler options." | |||
| #endif | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led4; | |||
| /*! | |||
| * \brief Function to be executed on Radio Rx Done event | |||
| */ | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); | |||
| /*! | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| // Radio initialization | |||
| RadioEvents.RxDone = OnRxDone; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetChannel( RF_FREQUENCY ); | |||
| #if defined( USE_MODEM_LORA ) | |||
| Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, | |||
| LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, | |||
| LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, | |||
| 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); | |||
| #elif defined( USE_MODEM_FSK ) | |||
| Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, | |||
| 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, | |||
| 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true, | |||
| 0, 0, false, true ); | |||
| Radio.SetMaxPayloadLength( MODEM_FSK, 255 ); | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| Radio.Rx( 0 ); // Continuous Rx | |||
| while( 1 ) | |||
| { | |||
| BoardLowPowerHandler( ); | |||
| } | |||
| } | |||
| void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) | |||
| { | |||
| static uint8_t ledState = 1; | |||
| // Toggle LED 4 | |||
| ledState ^= 1; | |||
| GpioWrite( &Led4, ledState ); | |||
| } | |||
| @@ -0,0 +1,203 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Tx Continuous Wave implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_TIMEOUT 65535 // seconds (MAX value) | |||
| static TimerEvent_t Led1Timer; | |||
| volatile bool Led1TimerEvent = false; | |||
| static TimerEvent_t Led2Timer; | |||
| volatile bool Led2TimerEvent = false; | |||
| static TimerEvent_t Led3Timer; | |||
| volatile bool Led3TimerEvent = false; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| extern Gpio_t Led3; | |||
| /*! | |||
| * \brief Function executed on Led 1 Timeout event | |||
| */ | |||
| void OnLed1TimerEvent( void* context ) | |||
| { | |||
| Led1TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 2 Timeout event | |||
| */ | |||
| void OnLed2TimerEvent( void* context ) | |||
| { | |||
| Led2TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| void OnLed3TimerEvent( void* context ) | |||
| { | |||
| Led3TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnRadioTxTimeout( void ) | |||
| { | |||
| // Restarts continuous wave transmission when timeout expires | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| } | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 90 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 90 ); | |||
| TimerInit( &Led3Timer, OnLed3TimerEvent ); | |||
| TimerSetValue( &Led3Timer, 90 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| // Radio initialization | |||
| RadioEvents.TxTimeout = OnRadioTxTimeout; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| // Blink LEDs just to show some activity | |||
| while( 1 ) | |||
| { | |||
| if( Led1TimerEvent == true ) | |||
| { | |||
| Led1TimerEvent = false; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| if( Led2TimerEvent == true ) | |||
| { | |||
| Led2TimerEvent = false; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| // Switch LED 3 ON | |||
| GpioWrite( &Led3, 0 ); | |||
| TimerStart( &Led3Timer ); | |||
| } | |||
| if( Led3TimerEvent == true ) | |||
| { | |||
| Led3TimerEvent = false; | |||
| // Switch LED 3 OFF | |||
| GpioWrite( &Led3, 1 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,91 @@ | |||
| ## | |||
| ## ______ _ | |||
| ## / _____) _ | | | |||
| ## ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| ## \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| ## _____) ) ____| | | || |_| ____( (___| | | | | |||
| ## (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| ## (C)2013-2017 Semtech | |||
| ## ___ _____ _ ___ _ _____ ___ ___ ___ ___ | |||
| ## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| | |||
| ## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| | |||
| ## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| | |||
| ## embedded.connectivity.solutions.============== | |||
| ## | |||
| ## License: Revised BSD License, see LICENSE.TXT file included in the project | |||
| ## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) | |||
| ## | |||
| project(tx-cw) | |||
| cmake_minimum_required(VERSION 3.6) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Options | |||
| #--------------------------------------------------------------------------------------- | |||
| # Allow selection of region | |||
| option(REGION_EU868 "Region EU868" ON) | |||
| option(REGION_US915 "Region US915" OFF) | |||
| option(REGION_CN779 "Region CN779" OFF) | |||
| option(REGION_EU433 "Region EU433" OFF) | |||
| option(REGION_AU915 "Region AU915" OFF) | |||
| option(REGION_AS923 "Region AS923" OFF) | |||
| option(REGION_CN470 "Region CN470" OFF) | |||
| option(REGION_KR920 "Region KR920" OFF) | |||
| option(REGION_IN865 "Region IN865" OFF) | |||
| option(REGION_RU864 "Region RU864" OFF) | |||
| set(REGION_LIST REGION_EU868 REGION_US915 REGION_CN779 REGION_EU433 REGION_AU915 REGION_AS923 REGION_CN470 REGION_KR920 REGION_IN865 REGION_RU864) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Target | |||
| #--------------------------------------------------------------------------------------- | |||
| file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/${BOARD}/*.c") | |||
| add_executable(${PROJECT_NAME} | |||
| ${${PROJECT_NAME}_SOURCES} | |||
| $<TARGET_OBJECTS:system> | |||
| $<TARGET_OBJECTS:radio> | |||
| $<TARGET_OBJECTS:peripherals> | |||
| $<TARGET_OBJECTS:${BOARD}> | |||
| ) | |||
| # Loops through all regions and add compile time definitions for the enabled ones. | |||
| foreach( REGION ${REGION_LIST} ) | |||
| if(${REGION}) | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC -D"${REGION}") | |||
| endif() | |||
| endforeach() | |||
| target_compile_definitions(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:mac,INTERFACE_COMPILE_DEFINITIONS>> | |||
| ) | |||
| target_include_directories(${PROJECT_NAME} PUBLIC | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:system,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:radio,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:peripherals,INTERFACE_INCLUDE_DIRECTORIES>> | |||
| $<BUILD_INTERFACE:$<TARGET_PROPERTY:${BOARD},INTERFACE_INCLUDE_DIRECTORIES>> | |||
| ) | |||
| set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) | |||
| target_link_libraries(${PROJECT_NAME} m) | |||
| #--------------------------------------------------------------------------------------- | |||
| # Debugging and Binutils | |||
| #--------------------------------------------------------------------------------------- | |||
| include(gdb-helper) | |||
| include(binutils-arm-none-eabi) | |||
| # Generate debugger configurations | |||
| generate_run_gdb_stlink(${PROJECT_NAME}) | |||
| generate_run_gdb_openocd(${PROJECT_NAME}) | |||
| generate_vscode_launch_openocd(${PROJECT_NAME}) | |||
| # Print section sizes of target | |||
| print_section_sizes(${PROJECT_NAME}) | |||
| # Create output in hex and binary format | |||
| create_bin_output(${PROJECT_NAME}) | |||
| create_hex_output(${PROJECT_NAME}) | |||
| @@ -0,0 +1,188 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Tx Continuous Wave implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board-config.h" | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #define TX_TIMEOUT 65535 // seconds (MAX value) | |||
| static TimerEvent_t Led1Timer; | |||
| volatile bool Led1TimerEvent = false; | |||
| static TimerEvent_t Led2Timer; | |||
| volatile bool Led2TimerEvent = false; | |||
| static TimerEvent_t Led3Timer; | |||
| volatile bool Led3TimerEvent = false; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| extern Gpio_t Led3; | |||
| /*! | |||
| * \brief Function executed on Led 1 Timeout event | |||
| */ | |||
| void OnLed1TimerEvent( void* context ) | |||
| { | |||
| Led1TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 2 Timeout event | |||
| */ | |||
| void OnLed2TimerEvent( void* context ) | |||
| { | |||
| Led2TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 3 Timeout event | |||
| */ | |||
| void OnLed3TimerEvent( void* context ) | |||
| { | |||
| Led3TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnRadioTxTimeout( void ) | |||
| { | |||
| // Restarts continuous wave transmission when timeout expires | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| } | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 90 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 90 ); | |||
| TimerInit( &Led3Timer, OnLed3TimerEvent ); | |||
| TimerSetValue( &Led3Timer, 90 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| // Radio initialization | |||
| RadioEvents.TxTimeout = OnRadioTxTimeout; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| // Blink LEDs just to show some activity | |||
| while( 1 ) | |||
| { | |||
| if( Led1TimerEvent == true ) | |||
| { | |||
| Led1TimerEvent = false; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| if( Led2TimerEvent == true ) | |||
| { | |||
| Led2TimerEvent = false; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| // Switch LED 3 ON | |||
| GpioWrite( &Led3, 0 ); | |||
| TimerStart( &Led3Timer ); | |||
| } | |||
| if( Led3TimerEvent == true ) | |||
| { | |||
| Led3TimerEvent = false; | |||
| // Switch LED 3 OFF | |||
| GpioWrite( &Led3, 1 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,182 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Tx Continuous Wave implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_TIMEOUT 10 // seconds (MAX value) | |||
| static TimerEvent_t Led1Timer; | |||
| volatile bool Led1TimerEvent = false; | |||
| static TimerEvent_t Led2Timer; | |||
| volatile bool Led2TimerEvent = false; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function executed on Led 1 Timeout event | |||
| */ | |||
| void OnLed1TimerEvent( void* context ) | |||
| { | |||
| Led1TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 2 Timeout event | |||
| */ | |||
| void OnLed2TimerEvent( void* context ) | |||
| { | |||
| Led2TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnRadioTxTimeout( void ) | |||
| { | |||
| // Restarts continuous wave transmission when timeout expires | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| } | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 90 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 90 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| // Radio initialization | |||
| RadioEvents.TxTimeout = OnRadioTxTimeout; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| // Blink LEDs just to show some activity | |||
| while( 1 ) | |||
| { | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| if( Led1TimerEvent == true ) | |||
| { | |||
| Led1TimerEvent = false; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| if( Led2TimerEvent == true ) | |||
| { | |||
| Led2TimerEvent = false; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,182 @@ | |||
| /*! | |||
| * \file main.c | |||
| * | |||
| * \brief Tx Continuous Wave implementation | |||
| * | |||
| * \copyright Revised BSD License, see section \ref LICENSE. | |||
| * | |||
| * \code | |||
| * ______ _ | |||
| * / _____) _ | | | |||
| * ( (____ _____ ____ _| |_ _____ ____| |__ | |||
| * \____ \| ___ | (_ _) ___ |/ ___) _ \ | |||
| * _____) ) ____| | | || |_| ____( (___| | | | | |||
| * (______/|_____)_|_|_| \__)_____)\____)_| |_| | |||
| * (C)2013-2017 Semtech | |||
| * | |||
| * \endcode | |||
| * | |||
| * \author Miguel Luis ( Semtech ) | |||
| * | |||
| * \author Gregory Cristian ( Semtech ) | |||
| */ | |||
| #include "board.h" | |||
| #include "gpio.h" | |||
| #include "timer.h" | |||
| #include "radio.h" | |||
| #if defined( REGION_AS923 ) | |||
| #define RF_FREQUENCY 923000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_AU915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_CN470 ) | |||
| #define RF_FREQUENCY 470000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_CN779 ) | |||
| #define RF_FREQUENCY 779000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_EU433 ) | |||
| #define RF_FREQUENCY 433000000 // Hz | |||
| #define TX_OUTPUT_POWER 20 // 20 dBm | |||
| #elif defined( REGION_EU868 ) | |||
| #define RF_FREQUENCY 868000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_KR920 ) | |||
| #define RF_FREQUENCY 920000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_IN865 ) | |||
| #define RF_FREQUENCY 865000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_US915 ) | |||
| #define RF_FREQUENCY 915000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #elif defined( REGION_RU864 ) | |||
| #define RF_FREQUENCY 864000000 // Hz | |||
| #define TX_OUTPUT_POWER 14 // 14 dBm | |||
| #else | |||
| #error "Please define a frequency band in the compiler options." | |||
| #endif | |||
| #define TX_TIMEOUT 10 // seconds (MAX value) | |||
| static TimerEvent_t Led1Timer; | |||
| volatile bool Led1TimerEvent = false; | |||
| static TimerEvent_t Led2Timer; | |||
| volatile bool Led2TimerEvent = false; | |||
| /*! | |||
| * Radio events function pointer | |||
| */ | |||
| static RadioEvents_t RadioEvents; | |||
| /*! | |||
| * LED GPIO pins objects | |||
| */ | |||
| extern Gpio_t Led1; | |||
| extern Gpio_t Led2; | |||
| /*! | |||
| * \brief Function executed on Led 1 Timeout event | |||
| */ | |||
| void OnLed1TimerEvent( void* context ) | |||
| { | |||
| Led1TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Led 2 Timeout event | |||
| */ | |||
| void OnLed2TimerEvent( void* context ) | |||
| { | |||
| Led2TimerEvent = true; | |||
| } | |||
| /*! | |||
| * \brief Function executed on Radio Tx Timeout event | |||
| */ | |||
| void OnRadioTxTimeout( void ) | |||
| { | |||
| // Restarts continuous wave transmission when timeout expires | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| } | |||
| /** | |||
| * Main application entry point. | |||
| */ | |||
| int main( void ) | |||
| { | |||
| // Target board initialization | |||
| BoardInitMcu( ); | |||
| BoardInitPeriph( ); | |||
| TimerInit( &Led1Timer, OnLed1TimerEvent ); | |||
| TimerSetValue( &Led1Timer, 90 ); | |||
| TimerInit( &Led2Timer, OnLed2TimerEvent ); | |||
| TimerSetValue( &Led2Timer, 90 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| // Radio initialization | |||
| RadioEvents.TxTimeout = OnRadioTxTimeout; | |||
| Radio.Init( &RadioEvents ); | |||
| Radio.SetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT ); | |||
| // Blink LEDs just to show some activity | |||
| while( 1 ) | |||
| { | |||
| // Process Radio IRQ | |||
| if( Radio.IrqProcess != NULL ) | |||
| { | |||
| Radio.IrqProcess( ); | |||
| } | |||
| if( Led1TimerEvent == true ) | |||
| { | |||
| Led1TimerEvent = false; | |||
| // Switch LED 1 OFF | |||
| GpioWrite( &Led1, 1 ); | |||
| // Switch LED 2 ON | |||
| GpioWrite( &Led2, 0 ); | |||
| TimerStart( &Led2Timer ); | |||
| } | |||
| if( Led2TimerEvent == true ) | |||
| { | |||
| Led2TimerEvent = false; | |||
| // Switch LED 2 OFF | |||
| GpioWrite( &Led2, 1 ); | |||
| // Switch LED 1 ON | |||
| GpioWrite( &Led1, 0 ); | |||
| TimerStart( &Led1Timer ); | |||
| } | |||
| } | |||
| } | |||