Browse Source

Merge commit '247ed3545b7d83a266440e86188d33cf152389aa' as 'loramac'

irr_shared
John-Mark Gurney 3 years ago
parent
commit
a808d359e8
100 changed files with 27615 additions and 0 deletions
  1. +28
    -0
      loramac/.gitignore
  2. +6
    -0
      loramac/.gitmodules
  3. +18
    -0
      loramac/.vscode/c_cpp_properties.json
  4. +83
    -0
      loramac/.vscode/settings.json
  5. +1057
    -0
      loramac/CHANGELOG.md
  6. +21
    -0
      loramac/CMakeLists.txt
  7. +24
    -0
      loramac/LICENSE
  8. +395
    -0
      loramac/README.md
  9. +16
    -0
      loramac/SECURITY.md
  10. +50
    -0
      loramac/cmake/binutils-arm-none-eabi.cmake
  11. +101
    -0
      loramac/cmake/gdb-helper.cmake
  12. +40
    -0
      loramac/cmake/launch.json.in
  13. +5
    -0
      loramac/cmake/openocd-run.gdb.in
  14. +41
    -0
      loramac/cmake/samr34.cmake
  15. +6
    -0
      loramac/cmake/stlink-run.gdb.in
  16. +40
    -0
      loramac/cmake/stm32l0.cmake
  17. +40
    -0
      loramac/cmake/stm32l1.cmake
  18. +40
    -0
      loramac/cmake/stm32l4.cmake
  19. +90
    -0
      loramac/cmake/toolchain-arm-none-eabi.cmake
  20. +3
    -0
      loramac/doc/ATECC608A-TNGLORA.md
  21. +3
    -0
      loramac/doc/NAMote72-platform.md
  22. +37
    -0
      loramac/doc/NucleoLxxx-platform.md
  23. +5
    -0
      loramac/doc/SAMR34-platform.md
  24. +6
    -0
      loramac/doc/SKiM88xx-platform.md
  25. BIN
      loramac/doc/SX1276-Wing-Board-(03-91016-RA).pdf
  26. +260
    -0
      loramac/doc/development-environment.md
  27. BIN
      loramac/doc/images/vscode-cmake-build.png
  28. BIN
      loramac/doc/images/vscode-cmake-configure.png
  29. +222
    -0
      loramac/src/CMakeLists.txt
  30. +170
    -0
      loramac/src/apps/LoRaMac/CMakeLists.txt
  31. +257
    -0
      loramac/src/apps/LoRaMac/common/CayenneLpp.c
  32. +76
    -0
      loramac/src/apps/LoRaMac/common/CayenneLpp.h
  33. +63
    -0
      loramac/src/apps/LoRaMac/common/Commissioning.h
  34. +1046
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/LmHandler.c
  35. +349
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/LmHandler.h
  36. +124
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/LmHandlerTypes.h
  37. +751
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.c
  38. +143
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.h
  39. +146
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhPackage.h
  40. +372
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.c
  41. +49
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.h
  42. +590
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.c
  43. +60
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.h
  44. +529
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.c
  45. +92
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.h
  46. +457
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.c
  47. +47
    -0
      loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.h
  48. +428
    -0
      loramac/src/apps/LoRaMac/common/LmHandlerMsgDisplay.c
  49. +104
    -0
      loramac/src/apps/LoRaMac/common/LmHandlerMsgDisplay.h
  50. +272
    -0
      loramac/src/apps/LoRaMac/common/NvmDataMgmt.c
  51. +71
    -0
      loramac/src/apps/LoRaMac/common/NvmDataMgmt.h
  52. +56
    -0
      loramac/src/apps/LoRaMac/common/cli.c
  53. +41
    -0
      loramac/src/apps/LoRaMac/common/cli.h
  54. +33
    -0
      loramac/src/apps/LoRaMac/common/githubVersion.h
  55. +746
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/B-L072Z-LRWAN1/main.c
  56. +725
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/NAMote72/main.c
  57. +721
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/NucleoL073/main.c
  58. +721
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/NucleoL152/main.c
  59. +721
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/NucleoL476/main.c
  60. +666
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/SAMR34/main.c
  61. +697
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/SKiM880B/main.c
  62. +697
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/SKiM881AXL/main.c
  63. +697
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/SKiM980A/main.c
  64. +33
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/firmwareVersion.h
  65. +1041
    -0
      loramac/src/apps/LoRaMac/fuota-test-01/readme.md
  66. +597
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/B-L072Z-LRWAN1/main.c
  67. +616
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/NAMote72/main.c
  68. +571
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL073/main.c
  69. +571
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL152/main.c
  70. +571
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL476/main.c
  71. +573
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/SAMR34/main.c
  72. +586
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM880B/main.c
  73. +586
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM881AXL/main.c
  74. +586
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM980A/main.c
  75. +33
    -0
      loramac/src/apps/LoRaMac/periodic-uplink-lpp/firmwareVersion.h
  76. +369
    -0
      loramac/src/apps/ping-pong/B-L072Z-LRWAN1/main.c
  77. +105
    -0
      loramac/src/apps/ping-pong/CMakeLists.txt
  78. +362
    -0
      loramac/src/apps/ping-pong/NAMote72/main.c
  79. +373
    -0
      loramac/src/apps/ping-pong/NucleoL073/main.c
  80. +373
    -0
      loramac/src/apps/ping-pong/NucleoL152/main.c
  81. +373
    -0
      loramac/src/apps/ping-pong/NucleoL476/main.c
  82. +371
    -0
      loramac/src/apps/ping-pong/SAMR34/main.c
  83. +361
    -0
      loramac/src/apps/ping-pong/SKiM880B/main.c
  84. +361
    -0
      loramac/src/apps/ping-pong/SKiM881AXL/main.c
  85. +361
    -0
      loramac/src/apps/ping-pong/SKiM980A/main.c
  86. +172
    -0
      loramac/src/apps/rx-sensi/B-L072Z-LRWAN1/main.c
  87. +105
    -0
      loramac/src/apps/rx-sensi/CMakeLists.txt
  88. +165
    -0
      loramac/src/apps/rx-sensi/NAMote72/main.c
  89. +177
    -0
      loramac/src/apps/rx-sensi/NucleoL073/main.c
  90. +177
    -0
      loramac/src/apps/rx-sensi/NucleoL152/main.c
  91. +177
    -0
      loramac/src/apps/rx-sensi/NucleoL476/main.c
  92. +177
    -0
      loramac/src/apps/rx-sensi/SAMR34/main.c
  93. +164
    -0
      loramac/src/apps/rx-sensi/SKiM880B/main.c
  94. +164
    -0
      loramac/src/apps/rx-sensi/SKiM881AXL/main.c
  95. +164
    -0
      loramac/src/apps/rx-sensi/SKiM980A/main.c
  96. +203
    -0
      loramac/src/apps/tx-cw/B-L072Z-LRWAN1/main.c
  97. +91
    -0
      loramac/src/apps/tx-cw/CMakeLists.txt
  98. +188
    -0
      loramac/src/apps/tx-cw/NAMote72/main.c
  99. +182
    -0
      loramac/src/apps/tx-cw/NucleoL073/main.c
  100. +182
    -0
      loramac/src/apps/tx-cw/NucleoL152/main.c

+ 28
- 0
loramac/.gitignore View File

@@ -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/

+ 6
- 0
loramac/.gitmodules View File

@@ -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

+ 18
- 0
loramac/.vscode/c_cpp_properties.json View File

@@ -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
}

+ 83
- 0
loramac/.vscode/settings.json View File

@@ -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"
}
}

+ 1057
- 0
loramac/CHANGELOG.md
File diff suppressed because it is too large
View File


+ 21
- 0
loramac/CMakeLists.txt View File

@@ -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)

+ 24
- 0
loramac/LICENSE View File

@@ -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.

+ 395
- 0
loramac/README.md View File

@@ -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.
![cmake configure](doc/images/vscode-cmake-configure.png)
* Wait for configuration process to finish
* Click on "Build" to build the project.
![cmake build](doc/images/vscode-cmake-build.png)
* 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.
![cmake configure](doc/images/vscode-cmake-configure.png)
* Wait for configuration process to finish
* Click on "Build" to build the project.
![cmake build](doc/images/vscode-cmake-build.png)
* 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.

+ 16
- 0
loramac/SECURITY.md View File

@@ -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)

+ 50
- 0
loramac/cmake/binutils-arm-none-eabi.cmake View File

@@ -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()

+ 101
- 0
loramac/cmake/gdb-helper.cmake View File

@@ -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()

+ 40
- 0
loramac/cmake/launch.json.in View File

@@ -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@"
}
]
}

+ 5
- 0
loramac/cmake/openocd-run.gdb.in View File

@@ -0,0 +1,5 @@
file @TARGET_NAME@
target extended-remote localhost:3333
monitor reset halt
load
thbreak main

+ 41
- 0
loramac/cmake/samr34.cmake View File

@@ -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")

+ 6
- 0
loramac/cmake/stlink-run.gdb.in View File

@@ -0,0 +1,6 @@
file @TARGET_NAME@
target extended localhost:4242
monitor reset halt
shell sleep 1
load
thbreak main

+ 40
- 0
loramac/cmake/stm32l0.cmake View File

@@ -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")

+ 40
- 0
loramac/cmake/stm32l1.cmake View File

@@ -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")

+ 40
- 0
loramac/cmake/stm32l4.cmake View File

@@ -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")

+ 90
- 0
loramac/cmake/toolchain-arm-none-eabi.cmake View File

@@ -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)

+ 3
- 0
loramac/doc/ATECC608A-TNGLORA.md View File

@@ -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.

+ 3
- 0
loramac/doc/NAMote72-platform.md View File

@@ -0,0 +1,3 @@
# NAMote72 platform support documents

* [NAMote72](https://os.mbed.com/platforms/NAMote-72/)

+ 37
- 0
loramac/doc/NucleoLxxx-platform.md View File

@@ -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/)

+ 5
- 0
loramac/doc/SAMR34-platform.md View File

@@ -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)

+ 6
- 0
loramac/doc/SKiM88xx-platform.md View File

@@ -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)

BIN
loramac/doc/SX1276-Wing-Board-(03-91016-RA).pdf View File


+ 260
- 0
loramac/doc/development-environment.md View File

@@ -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.

BIN
loramac/doc/images/vscode-cmake-build.png View File

Before After
Width: 962  |  Height: 23  |  Size: 6.8 KiB

BIN
loramac/doc/images/vscode-cmake-configure.png View File

Before After
Width: 962  |  Height: 23  |  Size: 6.9 KiB

+ 222
- 0
loramac/src/CMakeLists.txt View File

@@ -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()

+ 170
- 0
loramac/src/apps/LoRaMac/CMakeLists.txt View File

@@ -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})

+ 257
- 0
loramac/src/apps/LoRaMac/common/CayenneLpp.c View File

@@ -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;
}

+ 76
- 0
loramac/src/apps/LoRaMac/common/CayenneLpp.h View File

@@ -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__

+ 63
- 0
loramac/src/apps/LoRaMac/common/Commissioning.h View File

@@ -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__

+ 1046
- 0
loramac/src/apps/LoRaMac/common/LmHandler/LmHandler.c
File diff suppressed because it is too large
View File


+ 349
- 0
loramac/src/apps/LoRaMac/common/LmHandler/LmHandler.h View File

@@ -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__

+ 124
- 0
loramac/src/apps/LoRaMac/common/LmHandler/LmHandlerTypes.h View File

@@ -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__

+ 751
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.c View File

@@ -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++;
}
}
}

+ 143
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.h View File

@@ -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__

+ 146
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhPackage.h View File

@@ -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__

+ 372
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.c View File

@@ -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 );
}

+ 49
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.h View File

@@ -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__

+ 590
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.c View File

@@ -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;
}

+ 60
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.h View File

@@ -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__

+ 529
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.c View File

@@ -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 );
}
}
}

+ 92
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.h View File

@@ -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__

+ 457
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.c View File

@@ -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;
}

+ 47
- 0
loramac/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.h View File

@@ -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__

+ 428
- 0
loramac/src/apps/LoRaMac/common/LmHandlerMsgDisplay.c View File

@@ -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" );
}

+ 104
- 0
loramac/src/apps/LoRaMac/common/LmHandlerMsgDisplay.h View File

@@ -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__

+ 272
- 0
loramac/src/apps/LoRaMac/common/NvmDataMgmt.c View File

@@ -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;
}

+ 71
- 0
loramac/src/apps/LoRaMac/common/NvmDataMgmt.h View File

@@ -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__

+ 56
- 0
loramac/src/apps/LoRaMac/common/cli.c View File

@@ -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 );
}
}
}
}

+ 41
- 0
loramac/src/apps/LoRaMac/common/cli.h View File

@@ -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

+ 33
- 0
loramac/src/apps/LoRaMac/common/githubVersion.h View File

@@ -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__

+ 746
- 0
loramac/src/apps/LoRaMac/fuota-test-01/B-L072Z-LRWAN1/main.c View File

@@ -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 );
}

+ 725
- 0
loramac/src/apps/LoRaMac/fuota-test-01/NAMote72/main.c View File

@@ -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 );
}

+ 721
- 0
loramac/src/apps/LoRaMac/fuota-test-01/NucleoL073/main.c View File

@@ -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 );
}

+ 721
- 0
loramac/src/apps/LoRaMac/fuota-test-01/NucleoL152/main.c View File

@@ -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 );
}

+ 721
- 0
loramac/src/apps/LoRaMac/fuota-test-01/NucleoL476/main.c View File

@@ -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 );
}

+ 666
- 0
loramac/src/apps/LoRaMac/fuota-test-01/SAMR34/main.c View File

@@ -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 );
}

+ 697
- 0
loramac/src/apps/LoRaMac/fuota-test-01/SKiM880B/main.c View File

@@ -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 );
}

+ 697
- 0
loramac/src/apps/LoRaMac/fuota-test-01/SKiM881AXL/main.c View File

@@ -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 );
}

+ 697
- 0
loramac/src/apps/LoRaMac/fuota-test-01/SKiM980A/main.c View File

@@ -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 );
}

+ 33
- 0
loramac/src/apps/LoRaMac/fuota-test-01/firmwareVersion.h View File

@@ -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__

+ 1041
- 0
loramac/src/apps/LoRaMac/fuota-test-01/readme.md
File diff suppressed because it is too large
View File


+ 597
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/B-L072Z-LRWAN1/main.c View File

@@ -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 );
}

+ 616
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/NAMote72/main.c View File

@@ -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 );
}

+ 571
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL073/main.c View File

@@ -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 );
}

+ 571
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL152/main.c View File

@@ -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 );
}

+ 571
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/NucleoL476/main.c View File

@@ -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 );
}

+ 573
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/SAMR34/main.c View File

@@ -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 );
}

+ 586
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM880B/main.c View File

@@ -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 );
}

+ 586
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM881AXL/main.c View File

@@ -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 );
}

+ 586
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/SKiM980A/main.c View File

@@ -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 );
}

+ 33
- 0
loramac/src/apps/LoRaMac/periodic-uplink-lpp/firmwareVersion.h View File

@@ -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__

+ 369
- 0
loramac/src/apps/ping-pong/B-L072Z-LRWAN1/main.c View File

@@ -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;
}

+ 105
- 0
loramac/src/apps/ping-pong/CMakeLists.txt View File

@@ -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})

+ 362
- 0
loramac/src/apps/ping-pong/NAMote72/main.c View File

@@ -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;
}

+ 373
- 0
loramac/src/apps/ping-pong/NucleoL073/main.c View File

@@ -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;
}

+ 373
- 0
loramac/src/apps/ping-pong/NucleoL152/main.c View File

@@ -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;
}

+ 373
- 0
loramac/src/apps/ping-pong/NucleoL476/main.c View File

@@ -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;
}

+ 371
- 0
loramac/src/apps/ping-pong/SAMR34/main.c View File

@@ -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;
}

+ 361
- 0
loramac/src/apps/ping-pong/SKiM880B/main.c View File

@@ -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;
}

+ 361
- 0
loramac/src/apps/ping-pong/SKiM881AXL/main.c View File

@@ -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;
}

+ 361
- 0
loramac/src/apps/ping-pong/SKiM980A/main.c View File

@@ -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;
}

+ 172
- 0
loramac/src/apps/rx-sensi/B-L072Z-LRWAN1/main.c View File

@@ -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 );
}

+ 105
- 0
loramac/src/apps/rx-sensi/CMakeLists.txt View File

@@ -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})

+ 165
- 0
loramac/src/apps/rx-sensi/NAMote72/main.c View File

@@ -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 );
}

+ 177
- 0
loramac/src/apps/rx-sensi/NucleoL073/main.c View File

@@ -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 );
}

+ 177
- 0
loramac/src/apps/rx-sensi/NucleoL152/main.c View File

@@ -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 );
}

+ 177
- 0
loramac/src/apps/rx-sensi/NucleoL476/main.c View File

@@ -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 );
}

+ 177
- 0
loramac/src/apps/rx-sensi/SAMR34/main.c View File

@@ -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 );
}

+ 164
- 0
loramac/src/apps/rx-sensi/SKiM880B/main.c View File

@@ -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 );
}

+ 164
- 0
loramac/src/apps/rx-sensi/SKiM881AXL/main.c View File

@@ -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 );
}

+ 164
- 0
loramac/src/apps/rx-sensi/SKiM980A/main.c View File

@@ -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 );
}

+ 203
- 0
loramac/src/apps/tx-cw/B-L072Z-LRWAN1/main.c View File

@@ -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 );
}
}
}

+ 91
- 0
loramac/src/apps/tx-cw/CMakeLists.txt View File

@@ -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})

+ 188
- 0
loramac/src/apps/tx-cw/NAMote72/main.c View File

@@ -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 );
}
}
}

+ 182
- 0
loramac/src/apps/tx-cw/NucleoL073/main.c View File

@@ -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 );
}
}
}

+ 182
- 0
loramac/src/apps/tx-cw/NucleoL152/main.c View File

@@ -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 );
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save