├── .github └── stale.yml ├── .gitignore ├── .gitmodules ├── API.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── default_dev_eui │ ├── CMakeLists.txt │ └── main.c ├── erase_nvm │ ├── CMakeLists.txt │ └── main.c ├── hello_abp │ ├── CMakeLists.txt │ ├── config.h │ └── main.c ├── hello_otaa │ ├── CMakeLists.txt │ ├── config.h │ └── main.c └── otaa_temperature_led │ ├── CMakeLists.txt │ ├── config.h │ └── main.c ├── pico_sdk_import.cmake └── src ├── LICENSE ├── boards └── rp2040 │ ├── LICENSE │ ├── board.c │ ├── delay-board.c │ ├── eeprom-board.c │ ├── gpio-board.c │ ├── rtc-board.c │ ├── spi-board.c │ └── sx1276-board.c ├── include └── pico │ └── lorawan.h └── lorawan.c /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - help wanted 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false 19 | # Never stale pull requests 20 | only: issues -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | 13 | build/ 14 | 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/LoRaMac-node"] 2 | path = lib/LoRaMac-node 3 | url = https://github.com/Lora-net/LoRaMac-node.git 4 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # pico-lorawan API 2 | 3 | ## Include Library 4 | 5 | ```c 6 | #include 7 | ``` 8 | 9 | ## Initialization 10 | 11 | ### SX1276 Settings 12 | 13 | ```c 14 | // pin configuration for SX1276 radio module 15 | struct lorawan_sx1276_settings sx1276_settings = { 16 | .spi = { 17 | .inst = PICO_DEFAULT_SPI_INSTANCE, // RP2040 SPI instance 18 | .mosi = PICO_DEFAULT_SPI_TX_PIN, // SPI MOSI GPIO 19 | .miso = PICO_DEFAULT_SPI_RX_PIN, // SPI MISO GPIO 20 | .sck = PICO_DEFAULT_SPI_SCK_PIN, // SPI SCK GPIO 21 | .nss = 8. // SPI NSS / CS GPIO 22 | }, 23 | .reset = 9, // SX1276 RESET GPIO 24 | .dio0 = 7, // SX1276 DIO0 / G0 GPIO 25 | .dio1 = 10 // SX1276 DIO0 / G1 GPIO 26 | }; 27 | ``` 28 | 29 | ### ABP 30 | 31 | Initialize the library for ABP. 32 | 33 | ```c 34 | // ABP settings 35 | const struct lorawan_abp_settings abp_settings = { 36 | // LoRaWAN device address (32-bit) 37 | .device_address = "00000000", 38 | 39 | // LoRaWAN Network Session Key (128-bit) 40 | .network_session_key = "00000000000000000000000000000000", 41 | 42 | // LoRaWAN Application Session Key (128-bit) 43 | .app_session_key = "00000000000000000000000000000000", 44 | 45 | // LoRaWAN Channel Mask, NULL value will use the default channel mask 46 | // for US915 with TTN use "FF0000000000000000020000" 47 | .channel_mask = NULL, 48 | }; 49 | 50 | int lorawan_init_abp(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_abp_settings* abp_settings); 51 | ``` 52 | 53 | - `sx1276_settings` - pointer to settings for SX1276 SPI and GPIO pins 54 | - `region` - region to use, see [`enum LoRaMacRegion_t 55 | `](http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec)for supported values] 56 | - `abp_settings` - pointer to LoRaWAN ABP settings 57 | 58 | Returns `0` on success, `-1` on error. 59 | 60 | ### OTAA 61 | 62 | Initialize the library for OTAA. 63 | 64 | ```c 65 | const struct lorawan_otaa_settings otaa_settings = { 66 | // LoRaWAN Device EUI (64-bit), NULL value will use Default Dev EUI 67 | .device_eui = "0000000000000000", 68 | 69 | // LoRaWAN Application / Join EUI (64-bit) 70 | .app_eui = "0000000000000000", 71 | 72 | // LoRaWAN Application Key (128-bit) 73 | .app_key = "00000000000000000000000000000000", 74 | 75 | // LoRaWAN Channel Mask, NULL value will use the default channel mask 76 | // for US915 with TTN use "FF0000000000000000020000" 77 | .channel_mask = NULL, 78 | }; 79 | 80 | int lorawan_init_otaa(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_otaa_settings* otaa_settings); 81 | ``` 82 | 83 | - `sx1276_settings` - pointer to settings for SX1276 SPI and GPIO pins 84 | - `region` - region to use, see [`enum LoRaMacRegion_t 85 | `](http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec)for supported values] 86 | - `otaa_settings` - pointer to LoRaWAN OTAA settings 87 | 88 | Returns `0` on success, `-1` on error. 89 | 90 | 91 | ## Joining 92 | 93 | ### Start Join 94 | 95 | Start the LoRaWAN network join process. 96 | 97 | ```c 98 | int lorawan_join(); 99 | ``` 100 | 101 | Returns `0` on success, `-1` on error. 102 | 103 | ### Join Status 104 | 105 | Query the LoRaWAN network join status. 106 | 107 | ```c 108 | int lorawan_is_joined(); 109 | ``` 110 | 111 | Returns `1` if the board has successfully joined the LoRaWAN network, `0` otherwise. 112 | 113 | ## Processing Pending Events 114 | 115 | ### Without Timeout 116 | 117 | Let the LoRaWAN library process pending events. 118 | 119 | ```c 120 | int lorawan_process(); 121 | ``` 122 | 123 | Returns `0` if there is a pending event, `1` if there are no pending events and the calling application can go into low power sleep mode. 124 | 125 | ### With Timeout 126 | 127 | Let the lorwan library process pending events for up to `n` milliseconds. 128 | 129 | ```c 130 | int lorawan_process_timeout_ms(uint32_t timeout_ms); 131 | ``` 132 | 133 | - `timeout_ms` in milliseconds to wait for LoRaWAN event. 134 | 135 | Returns `0` on event, `1` on timeout. 136 | 137 | 138 | ## Sending Uplink Messages 139 | 140 | ### Unconfirmed 141 | 142 | Send an unconfirmed uplink message. 143 | 144 | ```c 145 | int lorawan_send_unconfirmed(const void* data, uint8_t data_len, uint8_t app_port); 146 | ``` 147 | 148 | - `data` - message data buffer to send 149 | - `data_len` - size of message in bytes 150 | - `app_port` - application port to use for message 151 | 152 | Returns `0` on success, `-1` on failure. 153 | 154 | ## Receiving Downlink Messages 155 | 156 | ```c 157 | int lorawan_receive(void* data, uint8_t data_len, uint8_t* app_port); 158 | ``` 159 | 160 | - `data` - message data buffer to store received data 161 | - `data_len` - size of message data buffer in bytes 162 | - `app_port` - pointer to store application port of received message 163 | 164 | Returns length of received message on success, `-1` on failure. 165 | 166 | ## Other 167 | 168 | ### Default Dev EUI 169 | 170 | Read the board's default Dev EUI Dev EUI which is based on the Pico SDK's [pico_get_unique_board_id(...)](https://raspberrypi.github.io/pico-sdk-doxygen/group__pico__unique__id.html) API which uses the on board NOR flash device 64-bit unique ID. 171 | 172 | ```c 173 | const char* lorawan_default_dev_eui(char* dev_eui); 174 | ``` 175 | 176 | - `dev_eui` - 17 byte buffer to store default Dev EUI as c-string 177 | 178 | Returns `dev_eui` argument. 179 | 180 | ### Debugging Ouput 181 | 182 | Enable or disable debug output from the library. 183 | 184 | ```c 185 | void lorawan_debug(bool debug); 186 | ``` 187 | 188 | - `debug` - `true` to enable debug output, `false` to disable debug output 189 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # initialize pico_sdk from GIT 4 | # (note this can come from environment, CMake cache etc) 5 | # set(PICO_SDK_FETCH_FROM_GIT on) 6 | 7 | # pico_sdk_import.cmake is a single file copied from this SDK 8 | # note: this must happen before project() 9 | include(pico_sdk_import.cmake) 10 | 11 | project(pico_lorawan) 12 | 13 | # initialize the Pico SDK 14 | pico_sdk_init() 15 | 16 | set(LORAMAC_NODE_PATH ${CMAKE_CURRENT_LIST_DIR}/lib/LoRaMac-node) 17 | 18 | add_library(pico_loramac_node INTERFACE) 19 | 20 | target_sources(pico_loramac_node INTERFACE 21 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/CayenneLpp.c 22 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/cli.c 23 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandlerMsgDisplay.c 24 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/NvmDataMgmt.c 25 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/LmHandler.c 26 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.c 27 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.c 28 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.c 29 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.c 30 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.c 31 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/NvmDataMgmt.c 32 | 33 | ${LORAMAC_NODE_PATH}/src/boards/mcu/utilities.c 34 | 35 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/NvmDataMgmt.c 36 | 37 | ${LORAMAC_NODE_PATH}/src/mac/region/Region.c 38 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionAS923.c 39 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionAU915.c 40 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionBaseUS.c 41 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN470.c 42 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN470A20.c 43 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN470A26.c 44 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN470B20.c 45 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN470B26.c 46 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCN779.c 47 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionCommon.c 48 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionEU433.c 49 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionEU868.c 50 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionIN865.c 51 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionKR920.c 52 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionRU864.c 53 | ${LORAMAC_NODE_PATH}/src/mac/region/RegionUS915.c 54 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMac.c 55 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacAdr.c 56 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacClassB.c 57 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacCommands.c 58 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacConfirmQueue.c 59 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacCrypto.c 60 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacParser.c 61 | ${LORAMAC_NODE_PATH}/src/mac/LoRaMacSerializer.c 62 | 63 | ${LORAMAC_NODE_PATH}/src/peripherals/soft-se/aes.c 64 | ${LORAMAC_NODE_PATH}/src/peripherals/soft-se/cmac.c 65 | ${LORAMAC_NODE_PATH}/src/peripherals/soft-se/soft-se-hal.c 66 | ${LORAMAC_NODE_PATH}/src/peripherals/soft-se/soft-se.c 67 | 68 | ${LORAMAC_NODE_PATH}/src/radio/sx1276/sx1276.c 69 | 70 | ${LORAMAC_NODE_PATH}/src/system/delay.c 71 | ${LORAMAC_NODE_PATH}/src/system/gpio.c 72 | ${LORAMAC_NODE_PATH}/src/system/nvmm.c 73 | ${LORAMAC_NODE_PATH}/src/system/systime.c 74 | ${LORAMAC_NODE_PATH}/src/system/timer.c 75 | 76 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/board.c 77 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/delay-board.c 78 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/eeprom-board.c 79 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/gpio-board.c 80 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/rtc-board.c 81 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/spi-board.c 82 | ${CMAKE_CURRENT_LIST_DIR}/src/boards/rp2040/sx1276-board.c 83 | ) 84 | 85 | target_include_directories(pico_loramac_node INTERFACE 86 | ${LORAMAC_NODE_PATH}/src 87 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common 88 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler 89 | ${LORAMAC_NODE_PATH}/src/apps/LoRaMac/common/LmHandler/packages 90 | ${LORAMAC_NODE_PATH}/src/boards 91 | ${LORAMAC_NODE_PATH}/src/mac 92 | ${LORAMAC_NODE_PATH}/src/mac/region 93 | ${LORAMAC_NODE_PATH}/src/peripherals/soft-se 94 | ${LORAMAC_NODE_PATH}/src/radio 95 | ${LORAMAC_NODE_PATH}/src/system 96 | ) 97 | 98 | target_link_libraries(pico_loramac_node INTERFACE pico_stdlib pico_unique_id hardware_spi) 99 | 100 | target_compile_definitions(pico_loramac_node INTERFACE -DSOFT_SE) 101 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_EU868) 102 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_US915) 103 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_CN779) 104 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_EU433) 105 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_AU915) 106 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_AS923) 107 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_CN470) 108 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_KR920) 109 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_IN865) 110 | target_compile_definitions(pico_loramac_node INTERFACE -DREGION_RU864) 111 | target_compile_definitions(pico_loramac_node INTERFACE -DACTIVE_REGION=LORAMAC_REGION_US915) 112 | 113 | add_library(pico_lorawan INTERFACE) 114 | 115 | target_sources(pico_lorawan INTERFACE 116 | ${CMAKE_CURRENT_LIST_DIR}/src/lorawan.c 117 | ) 118 | 119 | target_include_directories(pico_lorawan INTERFACE 120 | ${CMAKE_CURRENT_LIST_DIR}/src/include 121 | ) 122 | 123 | target_link_libraries(pico_lorawan INTERFACE pico_loramac_node) 124 | 125 | add_subdirectory("examples/default_dev_eui") 126 | add_subdirectory("examples/erase_nvm") 127 | add_subdirectory("examples/hello_abp") 128 | add_subdirectory("examples/hello_otaa") 129 | add_subdirectory("examples/otaa_temperature_led") 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Arm Limited 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pico-lorawan 2 | Enable LoRaWAN communications on your [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) or any RP2040 based board using a [Semtech SX1276 radio module](https://www.semtech.com/apps/product.php?pn=SX1276). 3 | 4 | Based on the Semtech's [LoRaWAN end-device stack implementation and example projects](https://github.com/Lora-net/LoRaMac-node). 5 | 6 | ## Hardware 7 | 8 | * RP2040 board 9 | * [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) 10 | * [Adafruit Feather RP2040](https://www.adafruit.com/product/4884) 11 | * Semtech SX1276 board 12 | * [Adafruit RFM95W LoRa Radio Transceiver Breakout - 868 or 915 MHz - RadioFruit](https://www.adafruit.com/product/3072) 13 | * [Adafruit LoRa Radio FeatherWing - RFM95W 900 MHz - RadioFruit](https://www.adafruit.com/product/3231) 14 | 15 | ### Default Pinout 16 | 17 | | Raspberry Pi Pico / RP2040 | Semtech SX1276 | 18 | | ----------------- | -------------- | 19 | | 3.3V | VCC | 20 | | GND | GND | 21 | | GPIO 18 | SCK | 22 | | GPIO 19 | MOSI | 23 | | GPIO 16 | MISO | 24 | | GPIO 7 | DIO0 / G0 | 25 | | GPIO 8 | NSS / CS | 26 | | GPIO 9 | RESET | 27 | | GPIO 10 | DIO1 / G1 | 28 | 29 | GPIO pins are configurable in examples or API. 30 | 31 | ## Examples 32 | 33 | See [examples](examples/) folder. 34 | 35 | There is a `config.h` file to your ABP or OTAA node configuration for each example. 36 | 37 | ## Cloning 38 | 39 | ```sh 40 | git clone --recurse-submodules https://github.com/sandeepmistry/pico-lorawan.git 41 | ``` 42 | 43 | ## Building 44 | 45 | 1. [Set up the Pico C/C++ SDK](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf) 46 | 2. Set `PICO_SDK_PATH` 47 | ```sh 48 | export PICO_SDK_PATH=/path/to/pico-sdk 49 | ``` 50 | 3. Create `build` dir, run `cmake` and `make`: 51 | ``` 52 | mkdir build 53 | cd build 54 | cmake .. -DPICO_BOARD=pico 55 | make 56 | ``` 57 | 4. Copy example `.uf2` to Pico when in BOOT mode. 58 | 59 | ## Erasing Non-volatile Memory (NVM) 60 | 61 | This library uses the last page of flash as non-volatile memory (NVM) storage. 62 | 63 | You can erase it using the [`erase_nvm` example](examples/nvm), when: 64 | 65 | * Changing the devices configuration 66 | * If your board is timing out with joining the network 67 | 68 | ## Acknowledgements 69 | 70 | A big thanks to [Alasdair Allan](https://github.com/aallan) for his initial testing of EU868 support! 71 | 72 | This project was created on behalf of the [Arm Software Developers](https://developer.arm.com/) team, follow them on Twitter: [@ArmSoftwareDev](https://twitter.com/armsoftwaredev) and YouTube: [Arm Software Developers](https://www.youtube.com/channel/UCHUAckhCfRom2EHDGxwhfOg) for more resources! 73 | 74 | -------------------------------------------------------------------------------- /examples/default_dev_eui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # rest of your project 4 | add_executable(pico_lorawan_default_dev_eui 5 | main.c 6 | ) 7 | 8 | target_link_libraries(pico_lorawan_default_dev_eui pico_lorawan) 9 | 10 | # enable usb output, disable uart output 11 | pico_enable_stdio_usb(pico_lorawan_default_dev_eui 1) 12 | pico_enable_stdio_uart(pico_lorawan_default_dev_eui 0) 13 | 14 | # create map/bin/hex/uf2 file in addition to ELF. 15 | pico_add_extra_outputs(pico_lorawan_default_dev_eui) 16 | -------------------------------------------------------------------------------- /examples/default_dev_eui/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * 7 | * This example displays devices default LoRaWAN Dev EUI which is based 8 | * on the Pico SDK's pico_get_unique_board_id(...) API which uses the 9 | * on board NOR flash device 64-bit unique ID. 10 | * 11 | * https://raspberrypi.github.io/pico-sdk-doxygen/group__pico__unique__id.html 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | #include "pico/stdlib.h" 19 | #include "pico/lorawan.h" 20 | #include "tusb.h" 21 | 22 | int main(void) 23 | { 24 | char devEui[17]; 25 | 26 | // initialize stdio and wait for USB CDC connect 27 | stdio_init_all(); 28 | 29 | while (!tud_cdc_connected()) { 30 | tight_loop_contents(); 31 | } 32 | 33 | // get the default Dev EUI as a string and print it out 34 | printf("Pico LoRaWAN - Default Dev EUI = %s\n", lorawan_default_dev_eui(devEui)); 35 | 36 | // do nothing 37 | while (1) { 38 | tight_loop_contents(); 39 | } 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /examples/erase_nvm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # rest of your project 4 | add_executable(pico_lorawan_erase_nvm 5 | main.c 6 | ) 7 | 8 | target_link_libraries(pico_lorawan_erase_nvm pico_lorawan) 9 | 10 | # enable usb output, disable uart output 11 | pico_enable_stdio_usb(pico_lorawan_erase_nvm 1) 12 | pico_enable_stdio_uart(pico_lorawan_erase_nvm 0) 13 | 14 | # create map/bin/hex/uf2 file in addition to ELF. 15 | pico_add_extra_outputs(pico_lorawan_erase_nvm) 16 | -------------------------------------------------------------------------------- /examples/erase_nvm/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * 7 | * This example can be used to erase the NVM storage on a device. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include "pico/stdlib.h" 15 | #include "pico/lorawan.h" 16 | #include "tusb.h" 17 | 18 | // pin configuration for SX1276 radio module 19 | const struct lorawan_sx1276_settings sx1276_settings = { 20 | .spi = { 21 | .inst = PICO_DEFAULT_SPI_INSTANCE(), 22 | .mosi = PICO_DEFAULT_SPI_TX_PIN, 23 | .miso = PICO_DEFAULT_SPI_RX_PIN, 24 | .sck = PICO_DEFAULT_SPI_SCK_PIN, 25 | .nss = 8 26 | }, 27 | .reset = 9, 28 | .dio0 = 7, 29 | .dio1 = 10 30 | }; 31 | 32 | // LoRaWAN region to use, full list of regions can be found at: 33 | // http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec 34 | #define LORAWAN_REGION LORAMAC_REGION_US915 35 | 36 | int main( void ) 37 | { 38 | // initialize stdio and wait for USB CDC connect 39 | stdio_init_all(); 40 | 41 | while (!tud_cdc_connected()) { 42 | tight_loop_contents(); 43 | } 44 | printf("Pico LoRaWAN - Erase NVRAM\n\n"); 45 | 46 | // initialize the LoRaWAN stack 47 | printf("Initilizating LoRaWAN ... "); 48 | if (lorawan_init(&sx1276_settings, LORAWAN_REGION) < 0) { 49 | printf("failed!!!\n"); 50 | while (1) { 51 | tight_loop_contents(); 52 | } 53 | } else { 54 | printf("success!\n"); 55 | } 56 | 57 | printf("Erasing NVM ... "); 58 | if (lorawan_erase_nvm() < 0) { 59 | printf("failed!!!\n"); 60 | } else { 61 | printf("success!\n"); 62 | } 63 | 64 | while (1) { 65 | tight_loop_contents(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/hello_abp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # rest of your project 4 | add_executable(pico_lorawan_hello_abp 5 | main.c 6 | ) 7 | 8 | target_link_libraries(pico_lorawan_hello_abp pico_lorawan) 9 | 10 | # enable usb output, disable uart output 11 | pico_enable_stdio_usb(pico_lorawan_hello_abp 1) 12 | pico_enable_stdio_uart(pico_lorawan_hello_abp 0) 13 | 14 | # create map/bin/hex/uf2 file in addition to ELF. 15 | pico_add_extra_outputs(pico_lorawan_hello_abp) 16 | -------------------------------------------------------------------------------- /examples/hello_abp/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | // LoRaWAN region to use, full list of regions can be found at: 9 | // http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec 10 | #define LORAWAN_REGION LORAMAC_REGION_US915 11 | 12 | // LoRaWAN device address (32-bit) 13 | #define LORAWAN_DEV_ADDR "00000000" 14 | 15 | // LoRaWAN Network Session Key (128-bit) 16 | #define LORAWAN_NETWORK_SESSION_KEY "00000000000000000000000000000000" 17 | 18 | // LoRaWAN Application Session Key (128-bit) 19 | #define LORAWAN_APP_SESSION_KEY "00000000000000000000000000000000" 20 | 21 | // LoRaWAN Channel Mask, NULL value will use the default channel mask 22 | // for the region 23 | #define LORAWAN_CHANNEL_MASK NULL 24 | -------------------------------------------------------------------------------- /examples/hello_abp/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * 7 | * This example uses ABP to join the LoRaWAN network and then sends a 8 | * "hello world" uplink message periodically and prints out the 9 | * contents of any downlink message. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #include "pico/stdlib.h" 16 | #include "pico/lorawan.h" 17 | #include "tusb.h" 18 | 19 | // edit with LoRaWAN Node Region and ABP settings 20 | #include "config.h" 21 | 22 | // pin configuration for SX1276 radio module 23 | const struct lorawan_sx1276_settings sx1276_settings = { 24 | .spi = { 25 | .inst = PICO_DEFAULT_SPI_INSTANCE(), 26 | .mosi = PICO_DEFAULT_SPI_TX_PIN, 27 | .miso = PICO_DEFAULT_SPI_RX_PIN, 28 | .sck = PICO_DEFAULT_SPI_SCK_PIN, 29 | .nss = 8 30 | }, 31 | .reset = 9, 32 | .dio0 = 7, 33 | .dio1 = 10 34 | }; 35 | 36 | // ABP settings 37 | const struct lorawan_abp_settings abp_settings = { 38 | .device_address = LORAWAN_DEV_ADDR, 39 | .network_session_key = LORAWAN_NETWORK_SESSION_KEY, 40 | .app_session_key = LORAWAN_APP_SESSION_KEY, 41 | .channel_mask = LORAWAN_CHANNEL_MASK 42 | }; 43 | 44 | // variables for receiving data 45 | int receive_length = 0; 46 | uint8_t receive_buffer[242]; 47 | uint8_t receive_port = 0; 48 | 49 | int main( void ) 50 | { 51 | // initialize stdio and wait for USB CDC connect 52 | stdio_init_all(); 53 | 54 | while (!tud_cdc_connected()) { 55 | tight_loop_contents(); 56 | } 57 | 58 | printf("Pico LoRaWAN - Hello ABP\n\n"); 59 | 60 | // uncomment next line to enable debug 61 | // lorawan_debug(true); 62 | 63 | // initialize the LoRaWAN stack 64 | printf("Initilizating LoRaWAN ... "); 65 | if (lorawan_init_abp(&sx1276_settings, LORAWAN_REGION, &abp_settings) < 0) { 66 | printf("failed!!!\n"); 67 | while (1) { 68 | tight_loop_contents(); 69 | } 70 | } else { 71 | printf("success!\n"); 72 | } 73 | 74 | // Start the join process and wait 75 | printf("Joining LoRaWAN network ... "); 76 | lorawan_join(); 77 | 78 | while (!lorawan_is_joined()) { 79 | lorawan_process(); 80 | } 81 | printf("joined successfully!\n"); 82 | 83 | uint32_t last_message_time = 0; 84 | 85 | // loop forever 86 | while (1) { 87 | // let the lorwan library process pending events 88 | lorawan_process(); 89 | 90 | // get the current time and see if 5 seconds have passed 91 | // since the last message was sent 92 | uint32_t now = to_ms_since_boot(get_absolute_time()); 93 | 94 | if ((now - last_message_time) > 5000) { 95 | const char* message = "hello world!"; 96 | 97 | // try to send an unconfirmed uplink message 98 | printf("sending unconfirmed message '%s' ... ", message); 99 | if (lorawan_send_unconfirmed(message, strlen(message), 2) < 0) { 100 | printf("failed!!!\n"); 101 | } else { 102 | printf("success!\n"); 103 | } 104 | 105 | last_message_time = now; 106 | } 107 | 108 | // check if a downlink message was received 109 | receive_length = lorawan_receive(receive_buffer, sizeof(receive_buffer), &receive_port); 110 | if (receive_length > -1) { 111 | printf("received a %d byte message on port %d: ", receive_length, receive_port); 112 | 113 | for (int i = 0; i < receive_length; i++) { 114 | printf("%02x", receive_buffer[i]); 115 | } 116 | printf("\n"); 117 | } 118 | } 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /examples/hello_otaa/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # rest of your project 4 | add_executable(pico_lorawan_hello_otaa 5 | main.c 6 | ) 7 | 8 | target_link_libraries(pico_lorawan_hello_otaa pico_lorawan) 9 | 10 | # enable usb output, disable uart output 11 | pico_enable_stdio_usb(pico_lorawan_hello_otaa 1) 12 | pico_enable_stdio_uart(pico_lorawan_hello_otaa 0) 13 | 14 | # create map/bin/hex/uf2 file in addition to ELF. 15 | pico_add_extra_outputs(pico_lorawan_hello_otaa) 16 | -------------------------------------------------------------------------------- /examples/hello_otaa/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | // LoRaWAN region to use, full list of regions can be found at: 9 | // http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec 10 | #define LORAWAN_REGION LORAMAC_REGION_US915 11 | 12 | // LoRaWAN Device EUI (64-bit), NULL value will use Default Dev EUI 13 | #define LORAWAN_DEVICE_EUI "0000000000000000" 14 | 15 | // LoRaWAN Application / Join EUI (64-bit) 16 | #define LORAWAN_APP_EUI "0000000000000000" 17 | 18 | // LoRaWAN Application Key (128-bit) 19 | #define LORAWAN_APP_KEY "00000000000000000000000000000000" 20 | 21 | // LoRaWAN Channel Mask, NULL value will use the default channel mask 22 | // for the region 23 | #define LORAWAN_CHANNEL_MASK NULL 24 | -------------------------------------------------------------------------------- /examples/hello_otaa/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * This example uses OTAA to join the LoRaWAN network and then sends a 7 | * "hello world" uplink message periodically and prints out the 8 | * contents of any downlink message. 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include "pico/stdlib.h" 15 | #include "pico/lorawan.h" 16 | #include "tusb.h" 17 | 18 | // edit with LoRaWAN Node Region and OTAA settings 19 | #include "config.h" 20 | 21 | // pin configuration for SX1276 radio module 22 | const struct lorawan_sx1276_settings sx1276_settings = { 23 | .spi = { 24 | .inst = PICO_DEFAULT_SPI_INSTANCE(), 25 | .mosi = PICO_DEFAULT_SPI_TX_PIN, 26 | .miso = PICO_DEFAULT_SPI_RX_PIN, 27 | .sck = PICO_DEFAULT_SPI_SCK_PIN, 28 | .nss = 8 29 | }, 30 | .reset = 9, 31 | .dio0 = 7, 32 | .dio1 = 10 33 | }; 34 | 35 | // OTAA settings 36 | const struct lorawan_otaa_settings otaa_settings = { 37 | .device_eui = LORAWAN_DEVICE_EUI, 38 | .app_eui = LORAWAN_APP_EUI, 39 | .app_key = LORAWAN_APP_KEY, 40 | .channel_mask = LORAWAN_CHANNEL_MASK 41 | }; 42 | 43 | // variables for receiving data 44 | int receive_length = 0; 45 | uint8_t receive_buffer[242]; 46 | uint8_t receive_port = 0; 47 | 48 | int main( void ) 49 | { 50 | // initialize stdio and wait for USB CDC connect 51 | stdio_init_all(); 52 | 53 | while (!tud_cdc_connected()) { 54 | tight_loop_contents(); 55 | } 56 | 57 | printf("Pico LoRaWAN - Hello OTAA\n\n"); 58 | 59 | // uncomment next line to enable debug 60 | // lorawan_debug(true); 61 | 62 | // initialize the LoRaWAN stack 63 | printf("Initilizating LoRaWAN ... "); 64 | if (lorawan_init_otaa(&sx1276_settings, LORAWAN_REGION, &otaa_settings) < 0) { 65 | printf("failed!!!\n"); 66 | while (1) { 67 | tight_loop_contents(); 68 | } 69 | } else { 70 | printf("success!\n"); 71 | } 72 | 73 | // Start the join process and wait 74 | printf("Joining LoRaWAN network ... "); 75 | lorawan_join(); 76 | 77 | while (!lorawan_is_joined()) { 78 | lorawan_process(); 79 | } 80 | printf("joined successfully!\n"); 81 | 82 | uint32_t last_message_time = 0; 83 | 84 | // loop forever 85 | while (1) { 86 | // let the lorwan library process pending events 87 | lorawan_process(); 88 | 89 | // get the current time and see if 5 seconds have passed 90 | // since the last message was sent 91 | uint32_t now = to_ms_since_boot(get_absolute_time()); 92 | 93 | if ((now - last_message_time) > 5000) { 94 | const char* message = "hello world!"; 95 | 96 | // try to send an unconfirmed uplink message 97 | printf("sending unconfirmed message '%s' ... ", message); 98 | if (lorawan_send_unconfirmed(message, strlen(message), 2) < 0) { 99 | printf("failed!!!\n"); 100 | } else { 101 | printf("success!\n"); 102 | } 103 | 104 | last_message_time = now; 105 | } 106 | 107 | // check if a downlink message was received 108 | receive_length = lorawan_receive(receive_buffer, sizeof(receive_buffer), &receive_port); 109 | if (receive_length > -1) { 110 | printf("received a %d byte message on port %d: ", receive_length, receive_port); 111 | 112 | for (int i = 0; i < receive_length; i++) { 113 | printf("%02x", receive_buffer[i]); 114 | } 115 | printf("\n"); 116 | } 117 | } 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /examples/otaa_temperature_led/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # rest of your project 4 | add_executable(pico_lorawan_otaa_temperature_led 5 | main.c 6 | ) 7 | 8 | target_link_libraries(pico_lorawan_otaa_temperature_led pico_lorawan hardware_adc) 9 | 10 | # enable usb output, disable uart output 11 | pico_enable_stdio_usb(pico_lorawan_otaa_temperature_led 1) 12 | pico_enable_stdio_uart(pico_lorawan_otaa_temperature_led 0) 13 | 14 | # create map/bin/hex/uf2 file in addition to ELF. 15 | pico_add_extra_outputs(pico_lorawan_otaa_temperature_led) 16 | -------------------------------------------------------------------------------- /examples/otaa_temperature_led/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | // LoRaWAN region to use, full list of regions can be found at: 9 | // http://stackforce.github.io/LoRaMac-doc/LoRaMac-doc-v4.5.1/group___l_o_r_a_m_a_c.html#ga3b9d54f0355b51e85df8b33fd1757eec 10 | #define LORAWAN_REGION LORAMAC_REGION_US915 11 | 12 | // LoRaWAN Device EUI (64-bit), NULL value will use Default Dev EUI 13 | #define LORAWAN_DEVICE_EUI "0000000000000000" 14 | 15 | // LoRaWAN Application / Join EUI (64-bit) 16 | #define LORAWAN_APP_EUI "0000000000000000" 17 | 18 | // LoRaWAN Application Key (128-bit) 19 | #define LORAWAN_APP_KEY "00000000000000000000000000000000" 20 | 21 | // LoRaWAN Channel Mask, NULL value will use the default channel mask 22 | // for the region 23 | #define LORAWAN_CHANNEL_MASK NULL 24 | -------------------------------------------------------------------------------- /examples/otaa_temperature_led/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * This example uses OTAA to join the LoRaWAN network and then sends the 7 | * internal temperature sensors value up as an uplink message periodically 8 | * and the first byte of any uplink messages received controls the boards 9 | * built-in LED. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #include "hardware/adc.h" 16 | #include "hardware/gpio.h" 17 | 18 | #include "pico/stdlib.h" 19 | #include "pico/lorawan.h" 20 | #include "tusb.h" 21 | 22 | // edit with LoRaWAN Node Region and OTAA settings 23 | #include "config.h" 24 | 25 | // pin configuration for SX1276 radio module 26 | const struct lorawan_sx1276_settings sx1276_settings = { 27 | .spi = { 28 | .inst = PICO_DEFAULT_SPI_INSTANCE(), 29 | .mosi = PICO_DEFAULT_SPI_TX_PIN, 30 | .miso = PICO_DEFAULT_SPI_RX_PIN, 31 | .sck = PICO_DEFAULT_SPI_SCK_PIN, 32 | .nss = 8 33 | }, 34 | .reset = 9, 35 | .dio0 = 7, 36 | .dio1 = 10 37 | }; 38 | 39 | // OTAA settings 40 | const struct lorawan_otaa_settings otaa_settings = { 41 | .device_eui = LORAWAN_DEVICE_EUI, 42 | .app_eui = LORAWAN_APP_EUI, 43 | .app_key = LORAWAN_APP_KEY, 44 | .channel_mask = LORAWAN_CHANNEL_MASK 45 | }; 46 | 47 | // variables for receiving data 48 | int receive_length = 0; 49 | uint8_t receive_buffer[242]; 50 | uint8_t receive_port = 0; 51 | 52 | // functions used in main 53 | void internal_temperature_init(); 54 | float internal_temperature_get(); 55 | 56 | int main( void ) 57 | { 58 | // initialize stdio and wait for USB CDC connect 59 | stdio_init_all(); 60 | while (!tud_cdc_connected()) { 61 | tight_loop_contents(); 62 | } 63 | 64 | printf("Pico LoRaWAN - OTAA - Temperature + LED\n\n"); 65 | 66 | // initialize the LED pin and internal temperature ADC 67 | gpio_init(PICO_DEFAULT_LED_PIN); 68 | gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); 69 | 70 | internal_temperature_init(); 71 | 72 | // uncomment next line to enable debug 73 | // lorawan_debug(true); 74 | 75 | // initialize the LoRaWAN stack 76 | printf("Initilizating LoRaWAN ... "); 77 | if (lorawan_init_otaa(&sx1276_settings, LORAWAN_REGION, &otaa_settings) < 0) { 78 | printf("failed!!!\n"); 79 | while (1) { 80 | tight_loop_contents(); 81 | } 82 | } else { 83 | printf("success!\n"); 84 | } 85 | 86 | // Start the join process and wait 87 | printf("Joining LoRaWAN network ..."); 88 | lorawan_join(); 89 | 90 | while (!lorawan_is_joined()) { 91 | lorawan_process_timeout_ms(1000); 92 | printf("."); 93 | } 94 | printf(" joined successfully!\n"); 95 | 96 | // loop forever 97 | while (1) { 98 | // get the internal temperature 99 | int8_t adc_temperature_byte = internal_temperature_get(); 100 | 101 | // send the internal temperature as a (signed) byte in an unconfirmed uplink message 102 | printf("sending internal temperature: %d °C (0x%02x)... ", adc_temperature_byte, adc_temperature_byte); 103 | if (lorawan_send_unconfirmed(&adc_temperature_byte, sizeof(adc_temperature_byte), 2) < 0) { 104 | printf("failed!!!\n"); 105 | } else { 106 | printf("success!\n"); 107 | } 108 | 109 | // wait for up to 30 seconds for an event 110 | if (lorawan_process_timeout_ms(30000) == 0) { 111 | // check if a downlink message was received 112 | receive_length = lorawan_receive(receive_buffer, sizeof(receive_buffer), &receive_port); 113 | if (receive_length > -1) { 114 | printf("received a %d byte message on port %d: ", receive_length, receive_port); 115 | 116 | for (int i = 0; i < receive_length; i++) { 117 | printf("%02x", receive_buffer[i]); 118 | } 119 | printf("\n"); 120 | 121 | // the first byte of the received message controls the on board LED 122 | gpio_put(PICO_DEFAULT_LED_PIN, receive_buffer[0]); 123 | } 124 | } 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | void internal_temperature_init() 131 | { 132 | adc_init(); 133 | adc_set_temp_sensor_enabled(true); 134 | adc_select_input(4); 135 | } 136 | 137 | float internal_temperature_get() 138 | { 139 | const float v_ref = 3.3; 140 | 141 | // select and read the ADC 142 | adc_select_input(4); 143 | uint16_t adc_raw = adc_read(); 144 | 145 | // convert the raw ADC value to a voltage 146 | float adc_voltage = adc_raw * v_ref / 4095.0f; 147 | 148 | // convert voltage to temperature, using the formula from 149 | // section 4.9.4 in the RP2040 datasheet 150 | // https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf 151 | float adc_temperature = 27.0 - ((adc_voltage - 0.706) / 0.001721); 152 | 153 | return adc_temperature; 154 | } 155 | -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /src/LICENSE: -------------------------------------------------------------------------------- 1 | Revised BSD License 2 | Copyright Semtech Corporation 2013. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Semtech corporation nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE LIABLE FOR ANY DIRECT, 19 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/boards/rp2040/LICENSE: -------------------------------------------------------------------------------- 1 | Revised BSD License 2 | Copyright Semtech Corporation 2013. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Semtech corporation nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE LIABLE FOR ANY DIRECT, 19 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/boards/rp2040/board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "pico.h" 12 | #include "pico/unique_id.h" 13 | #include "hardware/sync.h" 14 | 15 | #include "board.h" 16 | 17 | void BoardInitMcu( void ) 18 | { 19 | } 20 | 21 | void BoardInitPeriph( void ) 22 | { 23 | } 24 | 25 | void BoardLowPowerHandler( void ) 26 | { 27 | __wfi(); 28 | } 29 | 30 | uint8_t BoardGetBatteryLevel( void ) 31 | { 32 | return 0; 33 | } 34 | 35 | uint32_t BoardGetRandomSeed( void ) 36 | { 37 | uint8_t id[8]; 38 | 39 | BoardGetUniqueId(id); 40 | 41 | return (id[3] << 24) | (id[2] << 16) | (id[1] << 1) | id[0]; 42 | } 43 | 44 | void BoardGetUniqueId( uint8_t *id ) 45 | { 46 | pico_unique_board_id_t board_id; 47 | 48 | pico_get_unique_board_id(&board_id); 49 | 50 | memcpy(id, board_id.id, 8); 51 | } 52 | 53 | void BoardCriticalSectionBegin( uint32_t *mask ) 54 | { 55 | *mask = save_and_disable_interrupts(); 56 | } 57 | 58 | void BoardCriticalSectionEnd( uint32_t *mask ) 59 | { 60 | restore_interrupts(*mask); 61 | } 62 | 63 | void BoardResetMcu( void ) 64 | { 65 | } 66 | -------------------------------------------------------------------------------- /src/boards/rp2040/delay-board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include "hardware/timer.h" 9 | 10 | #include "delay-board.h" 11 | 12 | void DelayMsMcu( uint32_t ms ) 13 | { 14 | busy_wait_us_32(ms * 1000); 15 | } 16 | -------------------------------------------------------------------------------- /src/boards/rp2040/eeprom-board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include "pico/stdlib.h" 11 | #include "hardware/flash.h" 12 | 13 | #include "utilities.h" 14 | #include "eeprom-board.h" 15 | 16 | #define EEPROM_SIZE (FLASH_SECTOR_SIZE) 17 | #define EEPROM_OFFSET (PICO_FLASH_SIZE_BYTES - EEPROM_SIZE) 18 | #define EEPROM_ADDRESS ((const uint8_t*)(XIP_BASE + EEPROM_OFFSET)) 19 | 20 | static uint8_t eeprom_write_cache[EEPROM_SIZE]; 21 | 22 | void EepromMcuInit() 23 | { 24 | memcpy(eeprom_write_cache, EEPROM_ADDRESS, sizeof(eeprom_write_cache)); 25 | } 26 | 27 | uint8_t EepromMcuReadBuffer( uint16_t addr, uint8_t *buffer, uint16_t size ) 28 | { 29 | memcpy(buffer, eeprom_write_cache + addr, size); 30 | 31 | return SUCCESS; 32 | } 33 | 34 | uint8_t EepromMcuWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size ) 35 | { 36 | memcpy(eeprom_write_cache + addr, buffer, size); 37 | 38 | return SUCCESS; 39 | } 40 | 41 | uint8_t EepromMcuFlush() 42 | { 43 | uint32_t mask; 44 | 45 | BoardCriticalSectionBegin(&mask); 46 | 47 | flash_range_erase(EEPROM_OFFSET, sizeof(eeprom_write_cache)); 48 | flash_range_program(EEPROM_OFFSET, eeprom_write_cache, sizeof(eeprom_write_cache)); 49 | 50 | BoardCriticalSectionEnd(&mask); 51 | } 52 | -------------------------------------------------------------------------------- /src/boards/rp2040/gpio-board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include "hardware/gpio.h" 9 | 10 | #include "gpio-board.h" 11 | 12 | void GpioMcuInit( Gpio_t *obj, PinNames pin, PinModes mode, PinConfigs config, PinTypes type, uint32_t value ) 13 | { 14 | obj->pin = pin; 15 | 16 | if( pin == NC ) 17 | { 18 | return; 19 | } 20 | 21 | gpio_init(pin); 22 | 23 | if (mode == PIN_INPUT) 24 | { 25 | gpio_set_dir(pin, GPIO_IN); 26 | } 27 | else if (mode == PIN_OUTPUT) 28 | { 29 | gpio_set_dir(pin, GPIO_OUT); 30 | } 31 | 32 | if (config == PIN_PUSH_PULL) 33 | { 34 | if (type == PIN_NO_PULL) 35 | { 36 | gpio_disable_pulls(pin); 37 | } 38 | else if (type == PIN_PULL_UP) 39 | { 40 | gpio_pull_up(pin); 41 | } 42 | else if (type == PIN_PULL_DOWN) 43 | { 44 | gpio_pull_down(pin); 45 | } 46 | } 47 | 48 | if( mode == PIN_OUTPUT ) 49 | { 50 | GpioMcuWrite( obj, value ); 51 | } 52 | } 53 | 54 | void GpioMcuWrite( Gpio_t *obj, uint32_t value ) 55 | { 56 | gpio_put(obj->pin, value); 57 | } 58 | 59 | uint32_t GpioMcuRead( Gpio_t *obj ) 60 | { 61 | return gpio_get(obj->pin); 62 | } 63 | -------------------------------------------------------------------------------- /src/boards/rp2040/rtc-board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include "pico/time.h" 9 | #include "pico/stdlib.h" 10 | 11 | #include "rtc-board.h" 12 | 13 | static alarm_pool_t* rtc_alarm_pool = NULL; 14 | static absolute_time_t rtc_timer_context; 15 | static alarm_id_t last_rtc_alarm_id = -1; 16 | 17 | void RtcInit( void ) 18 | { 19 | rtc_alarm_pool = alarm_pool_create(2, 16); 20 | 21 | RtcSetTimerContext(); 22 | } 23 | 24 | uint32_t RtcGetCalendarTime( uint16_t *milliseconds ) 25 | { 26 | uint32_t now = to_ms_since_boot(get_absolute_time()); 27 | 28 | *milliseconds = (now % 1000); 29 | 30 | return (now / 1000); 31 | } 32 | 33 | void RtcBkupRead( uint32_t *data0, uint32_t *data1 ) 34 | { 35 | *data0 = 0; 36 | *data1 = 0; 37 | } 38 | 39 | uint32_t RtcGetTimerElapsedTime( void ) 40 | { 41 | int64_t delta = absolute_time_diff_us(rtc_timer_context, get_absolute_time()); 42 | 43 | return delta; 44 | } 45 | 46 | uint32_t RtcSetTimerContext( void ) 47 | { 48 | rtc_timer_context = get_absolute_time(); 49 | 50 | uint64_t ticks = to_us_since_boot(rtc_timer_context); 51 | 52 | return ticks; 53 | } 54 | 55 | uint32_t RtcGetTimerContext( void ) 56 | { 57 | uint64_t ticks = to_us_since_boot(rtc_timer_context); 58 | 59 | return ticks; 60 | } 61 | 62 | uint32_t RtcGetMinimumTimeout( void ) 63 | { 64 | return 1; 65 | } 66 | 67 | static int64_t alarm_callback(alarm_id_t id, void *user_data) { 68 | TimerIrqHandler( ); 69 | 70 | return 0; 71 | } 72 | 73 | void RtcSetAlarm( uint32_t timeout ) 74 | { 75 | if (last_rtc_alarm_id > -1) { 76 | alarm_pool_cancel_alarm(rtc_alarm_pool, last_rtc_alarm_id); 77 | } 78 | 79 | last_rtc_alarm_id = alarm_pool_add_alarm_at(rtc_alarm_pool, delayed_by_us(rtc_timer_context, timeout), alarm_callback, NULL, true); 80 | } 81 | 82 | void RtcStopAlarm( void ) 83 | { 84 | if (last_rtc_alarm_id > -1) { 85 | alarm_pool_cancel_alarm(rtc_alarm_pool, last_rtc_alarm_id); 86 | } 87 | } 88 | 89 | uint32_t RtcMs2Tick( TimerTime_t milliseconds ) 90 | { 91 | return milliseconds * 1000; 92 | } 93 | 94 | uint32_t RtcGetTimerValue( void ) 95 | { 96 | uint64_t now = to_us_since_boot(get_absolute_time()); 97 | 98 | return now; 99 | } 100 | 101 | TimerTime_t RtcTick2Ms( uint32_t tick ) 102 | { 103 | return us_to_ms(tick); 104 | } 105 | 106 | void RtcBkupWrite( uint32_t data0, uint32_t data1 ) 107 | { 108 | } 109 | 110 | void RtcProcess( void ) 111 | { 112 | // Not used on this platform. 113 | } 114 | -------------------------------------------------------------------------------- /src/boards/rp2040/spi-board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include "pico/stdlib.h" 9 | #include "hardware/spi.h" 10 | 11 | #include "spi-board.h" 12 | 13 | void SpiInit( Spi_t *obj, SpiId_t spiId, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss ) 14 | { 15 | spi_init((spiId == 0) ? spi0 : spi1, 10 * 1000 * 1000); 16 | spi_set_format((spiId == 0) ? spi0 : spi1, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); 17 | gpio_set_function(mosi, GPIO_FUNC_SPI); 18 | gpio_set_function(miso, GPIO_FUNC_SPI); 19 | gpio_set_function(sclk, GPIO_FUNC_SPI); 20 | 21 | obj->SpiId = spiId; 22 | } 23 | 24 | uint16_t SpiInOut( Spi_t *obj, uint16_t outData ) 25 | { 26 | const uint8_t outDataB = (outData & 0xff); 27 | uint8_t inDataB = 0x00; 28 | 29 | spi_write_read_blocking((obj->SpiId == 0) ? spi0 : spi1, &outDataB, &inDataB, 1); 30 | 31 | return inDataB; 32 | } 33 | -------------------------------------------------------------------------------- /src/boards/rp2040/sx1276-board.c: -------------------------------------------------------------------------------- 1 | /*! 2 | * \file sx1276-board.c 3 | * 4 | * \brief Target board SX1276 driver implementation 5 | * 6 | * \remark This is based on 7 | * https://github.com/Lora-net/LoRaMac-node/blob/master/src/boards/B-L072Z-LRWAN1/sx1276-board.c 8 | * 9 | * \copyright Revised BSD License, see section \ref LICENSE. 10 | * 11 | * \code 12 | * ______ _ 13 | * / _____) _ | | 14 | * ( (____ _____ ____ _| |_ _____ ____| |__ 15 | * \____ \| ___ | (_ _) ___ |/ ___) _ \ 16 | * _____) ) ____| | | || |_| ____( (___| | | | 17 | * (______/|_____)_|_|_| \__)_____)\____)_| |_| 18 | * (C)2013-2017 Semtech 19 | * 20 | * \endcode 21 | * 22 | * \author Miguel Luis ( Semtech ) 23 | * 24 | * \author Gregory Cristian ( Semtech ) 25 | * 26 | */ 27 | 28 | #include 29 | 30 | #include "hardware/gpio.h" 31 | 32 | #include "delay.h" 33 | #include "sx1276-board.h" 34 | 35 | #include "radio/radio.h" 36 | 37 | const struct Radio_s Radio = 38 | { 39 | SX1276Init, 40 | SX1276GetStatus, 41 | SX1276SetModem, 42 | SX1276SetChannel, 43 | SX1276IsChannelFree, 44 | SX1276Random, 45 | SX1276SetRxConfig, 46 | SX1276SetTxConfig, 47 | SX1276CheckRfFrequency, 48 | SX1276GetTimeOnAir, 49 | SX1276Send, 50 | SX1276SetSleep, 51 | SX1276SetStby, 52 | SX1276SetRx, 53 | SX1276StartCad, 54 | SX1276SetTxContinuousWave, 55 | SX1276ReadRssi, 56 | SX1276Write, 57 | SX1276Read, 58 | SX1276WriteBuffer, 59 | SX1276ReadBuffer, 60 | SX1276SetMaxPayloadLength, 61 | SX1276SetPublicNetwork, 62 | SX1276GetWakeupTime, 63 | NULL, // void ( *IrqProcess )( void ) 64 | NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only 65 | NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only 66 | }; 67 | 68 | static DioIrqHandler** irq_handlers; 69 | 70 | void dio_gpio_callback(uint gpio, uint32_t events) 71 | { 72 | if (gpio == SX1276.DIO0.pin) { 73 | irq_handlers[0](NULL); 74 | } else if (gpio == SX1276.DIO1.pin) { 75 | irq_handlers[1](NULL); 76 | } 77 | } 78 | 79 | void SX1276SetAntSwLowPower( bool status ) 80 | { 81 | } 82 | 83 | bool SX1276CheckRfFrequency( uint32_t frequency ) 84 | { 85 | return true; 86 | } 87 | 88 | void SX1276SetBoardTcxo( uint8_t state ) 89 | { 90 | } 91 | 92 | uint32_t SX1276GetDio1PinState( void ) 93 | { 94 | return GpioRead(&SX1276.DIO1); 95 | } 96 | 97 | void SX1276SetAntSw( uint8_t opMode ) 98 | { 99 | } 100 | 101 | void SX1276Reset( void ) 102 | { 103 | GpioInit( &SX1276.Reset, SX1276.Reset.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 ); // RST 104 | 105 | DelayMs (1); 106 | 107 | GpioInit( &SX1276.Reset, SX1276.Reset.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 ); // RST 108 | 109 | DelayMs (6); 110 | } 111 | 112 | void SX1276IoInit( void ) 113 | { 114 | GpioInit( &SX1276.Spi.Nss, SX1276.Spi.Nss.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 ); // CS 115 | GpioInit( &SX1276.Reset, SX1276.Reset.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 ); // RST 116 | 117 | GpioInit( &SX1276.DIO0, SX1276.DIO0.pin, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 ); // IRQ / DIO0 118 | GpioInit( &SX1276.DIO1, SX1276.DIO1.pin, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 ); // DI01 119 | } 120 | 121 | void SX1276IoIrqInit( DioIrqHandler **irqHandlers ) 122 | { 123 | irq_handlers = irqHandlers; 124 | 125 | gpio_set_irq_enabled_with_callback(SX1276.DIO0.pin, GPIO_IRQ_EDGE_RISE, true, &dio_gpio_callback); 126 | gpio_set_irq_enabled_with_callback(SX1276.DIO1.pin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &dio_gpio_callback); 127 | } 128 | 129 | /*! 130 | * \brief Gets the board PA selection configuration 131 | * 132 | * \param [IN] power Selects the right PA according to the wanted power. 133 | * \retval PaSelect RegPaConfig PaSelect value 134 | */ 135 | static uint8_t SX1276GetPaSelect( int8_t power ); 136 | 137 | void SX1276SetRfTxPower( int8_t power ) 138 | { 139 | uint8_t paConfig = 0; 140 | uint8_t paDac = 0; 141 | 142 | paConfig = SX1276Read( REG_PACONFIG ); 143 | paDac = SX1276Read( REG_PADAC ); 144 | 145 | paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | SX1276GetPaSelect( power ); 146 | 147 | if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST ) 148 | { 149 | if( power > 17 ) 150 | { 151 | paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON; 152 | } 153 | else 154 | { 155 | paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF; 156 | } 157 | if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON ) 158 | { 159 | if( power < 5 ) 160 | { 161 | power = 5; 162 | } 163 | if( power > 20 ) 164 | { 165 | power = 20; 166 | } 167 | paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F ); 168 | } 169 | else 170 | { 171 | if( power < 2 ) 172 | { 173 | power = 2; 174 | } 175 | if( power > 17 ) 176 | { 177 | power = 17; 178 | } 179 | paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F ); 180 | } 181 | } 182 | else 183 | { 184 | if( power > 0 ) 185 | { 186 | if( power > 15 ) 187 | { 188 | power = 15; 189 | } 190 | paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 7 << 4 ) | ( power ); 191 | } 192 | else 193 | { 194 | if( power < -4 ) 195 | { 196 | power = -4; 197 | } 198 | paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 0 << 4 ) | ( power + 4 ); 199 | } 200 | } 201 | SX1276Write( REG_PACONFIG, paConfig ); 202 | SX1276Write( REG_PADAC, paDac ); 203 | } 204 | 205 | static uint8_t SX1276GetPaSelect( int8_t power ) 206 | { 207 | if( power > 14 ) 208 | { 209 | return RF_PACONFIG_PASELECT_PABOOST; 210 | } 211 | else 212 | { 213 | return RF_PACONFIG_PASELECT_RFO; 214 | } 215 | } 216 | 217 | uint32_t SX1276GetBoardTcxoWakeupTime( void ) 218 | { 219 | return 0; 220 | } 221 | -------------------------------------------------------------------------------- /src/include/pico/lorawan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #ifndef _PICO_LORAWAN_H_ 9 | #define _PICO_LORAWAN_H_ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #include "hardware/gpio.h" 16 | #include "hardware/spi.h" 17 | 18 | #include "LoRaMac.h" 19 | 20 | struct lorawan_sx1276_settings { 21 | struct { 22 | spi_inst_t* inst; 23 | uint mosi; 24 | uint miso; 25 | uint sck; 26 | uint nss; 27 | } spi; 28 | uint reset; 29 | uint dio0; 30 | uint dio1; 31 | }; 32 | 33 | struct lorawan_abp_settings { 34 | const char* device_address; 35 | const char* network_session_key; 36 | const char* app_session_key; 37 | const char* channel_mask; 38 | }; 39 | 40 | struct lorawan_otaa_settings { 41 | const char* device_eui; 42 | const char* app_eui; 43 | const char* app_key; 44 | const char* channel_mask; 45 | }; 46 | 47 | const char* lorawan_default_dev_eui(char* dev_eui); 48 | 49 | int lorawan_init(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region); 50 | 51 | int lorawan_init_abp(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_abp_settings* abp_settings); 52 | 53 | int lorawan_init_otaa(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_otaa_settings* otaa_settings); 54 | 55 | int lorawan_join(); 56 | 57 | int lorawan_is_joined(); 58 | 59 | int lorawan_process(); 60 | 61 | int lorawan_process_timeout_ms(uint32_t timeout_ms); 62 | 63 | int lorawan_send_unconfirmed(const void* data, uint8_t data_len, uint8_t app_port); 64 | 65 | int lorawan_receive(void* data, uint8_t data_len, uint8_t* app_port); 66 | 67 | void lorawan_debug(bool debug); 68 | 69 | int lorawan_erase_nvm(); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/lorawan.c: -------------------------------------------------------------------------------- 1 | /*! 2 | * \file lorawan.c 3 | * 4 | * \brief Implements the LoRaMac layer handling. 5 | * Provides the possibility to register applicative packages. 6 | * 7 | * \remark This file is based on 8 | * https://github.com/Lora-net/LoRaMac-node/blob/master/src/apps/LoRaMac/periodic-uplink-lpp/B-L072Z-LRWAN1/main.c 9 | * 10 | * \copyright Revised BSD License, see section \ref LICENSE. 11 | * 12 | * \code 13 | * ______ _ 14 | * / _____) _ | | 15 | * ( (____ _____ ____ _| |_ _____ ____| |__ 16 | * \____ \| ___ | (_ _) ___ |/ ___) _ \ 17 | * _____) ) ____| | | || |_| ____( (___| | | | 18 | * (______/|_____)_|_|_| \__)_____)\____)_| |_| 19 | * (C)2013-2018 Semtech 20 | * 21 | * \endcode 22 | * 23 | * \author Miguel Luis ( Semtech ) 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | #include "pico/lorawan.h" 31 | #include "pico/time.h" 32 | 33 | #include "board.h" 34 | #include "rtc-board.h" 35 | #include "sx1276-board.h" 36 | 37 | #include "../../periodic-uplink-lpp/firmwareVersion.h" 38 | #include "Commissioning.h" 39 | #include "RegionCommon.h" 40 | #include "LmHandler.h" 41 | #include "LmhpCompliance.h" 42 | #include "LmHandlerMsgDisplay.h" 43 | #include "NvmDataMgmt.h" 44 | 45 | /*! 46 | * LoRaWAN default end-device class 47 | */ 48 | #define LORAWAN_DEFAULT_CLASS CLASS_A 49 | 50 | /*! 51 | * LoRaWAN Adaptive Data Rate 52 | * 53 | * \remark Please note that when ADR is enabled the end-device should be static 54 | */ 55 | #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON 56 | 57 | /*! 58 | * Default datarate 59 | * 60 | * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled 61 | */ 62 | #define LORAWAN_DEFAULT_DATARATE DR_0 63 | 64 | /*! 65 | * LoRaWAN confirmed messages 66 | */ 67 | #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG 68 | 69 | /*! 70 | * User application data buffer size 71 | */ 72 | #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 73 | 74 | /*! 75 | * LoRaWAN ETSI duty cycle control enable/disable 76 | * 77 | * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes 78 | */ 79 | #define LORAWAN_DUTYCYCLE_ON true 80 | 81 | /*! 82 | * Indicates if the end-device is to be connected to a private or public network 83 | */ 84 | #define LORAWAN_PUBLIC_NETWORK true 85 | 86 | /*! 87 | * User application data 88 | */ 89 | static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; 90 | 91 | /*! 92 | * User application data structure 93 | */ 94 | static LmHandlerAppData_t AppData = 95 | { 96 | .Buffer = AppDataBuffer, 97 | .BufferSize = 0, 98 | .Port = 0, 99 | }; 100 | 101 | static void OnMacProcessNotify( void ); 102 | static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); 103 | static void OnNetworkParametersChange( CommissioningParams_t* params ); 104 | static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); 105 | static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); 106 | static void OnJoinRequest( LmHandlerJoinParams_t* params ); 107 | static void OnTxData( LmHandlerTxParams_t* params ); 108 | static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); 109 | static void OnClassChange( DeviceClass_t deviceClass ); 110 | static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); 111 | #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) 112 | static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); 113 | #else 114 | static void OnSysTimeUpdate( void ); 115 | #endif 116 | 117 | static void OnTxPeriodicityChanged( uint32_t periodicity ); 118 | static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); 119 | static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); 120 | 121 | static LmHandlerCallbacks_t LmHandlerCallbacks = 122 | { 123 | .GetBatteryLevel = BoardGetBatteryLevel, 124 | .GetTemperature = NULL, 125 | .GetRandomSeed = BoardGetRandomSeed, 126 | .OnMacProcess = OnMacProcessNotify, 127 | .OnNvmDataChange = OnNvmDataChange, 128 | .OnNetworkParametersChange = OnNetworkParametersChange, 129 | .OnMacMcpsRequest = OnMacMcpsRequest, 130 | .OnMacMlmeRequest = OnMacMlmeRequest, 131 | .OnJoinRequest = OnJoinRequest, 132 | .OnTxData = OnTxData, 133 | .OnRxData = OnRxData, 134 | .OnClassChange= OnClassChange, 135 | .OnBeaconStatusChange = OnBeaconStatusChange, 136 | .OnSysTimeUpdate = OnSysTimeUpdate, 137 | }; 138 | 139 | static LmHandlerParams_t LmHandlerParams = 140 | { 141 | .Region = ACTIVE_REGION, 142 | .AdrEnable = LORAWAN_ADR_STATE, 143 | .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, 144 | .TxDatarate = LORAWAN_DEFAULT_DATARATE, 145 | .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, 146 | .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, 147 | .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, 148 | .DataBuffer = AppDataBuffer, 149 | .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, 150 | }; 151 | 152 | static LmhpComplianceParams_t LmhpComplianceParams = 153 | { 154 | .FwVersion.Value = FIRMWARE_VERSION, 155 | .OnTxPeriodicityChanged = OnTxPeriodicityChanged, 156 | .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, 157 | .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, 158 | }; 159 | 160 | /*! 161 | * Indicates if LoRaMacProcess call is pending. 162 | * 163 | * \warning If variable is equal to 0 then the MCU can be set in low power mode 164 | */ 165 | static volatile uint8_t IsMacProcessPending = 0; 166 | 167 | static volatile uint32_t TxPeriodicity = 0; 168 | 169 | static const struct lorawan_abp_settings* AbpSettings = NULL; 170 | 171 | static const struct lorawan_otaa_settings* OtaaSettings = NULL; 172 | 173 | static uint8_t AppRxDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; 174 | 175 | static LmHandlerAppData_t AppRxData = 176 | { 177 | .Buffer = AppRxDataBuffer, 178 | .BufferSize = 0, 179 | .Port = 0, 180 | }; 181 | 182 | static bool Debug = false; 183 | 184 | extern void EepromMcuInit(); 185 | extern uint8_t EepromMcuFlush(); 186 | 187 | const char* lorawan_default_dev_eui(char* dev_eui) 188 | { 189 | uint8_t boardId[8]; 190 | 191 | BoardGetUniqueId(boardId); 192 | 193 | sprintf( 194 | dev_eui, "%02X%02X%02X%02X%02X%02X%02X%02X", 195 | boardId[0], boardId[1], boardId[2], boardId[3], 196 | boardId[4], boardId[5], boardId[6], boardId[7] 197 | ); 198 | 199 | return dev_eui; 200 | } 201 | 202 | int lorawan_init(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region) 203 | { 204 | EepromMcuInit(); 205 | 206 | RtcInit(); 207 | SpiInit( 208 | &SX1276.Spi, 209 | (SpiId_t)((sx1276_settings->spi.inst == spi0) ? 0 : 1), 210 | sx1276_settings->spi.mosi /*MOSI*/, 211 | sx1276_settings->spi.miso /*MISO*/, 212 | sx1276_settings->spi.sck /*SCK*/, 213 | NC 214 | ); 215 | 216 | SX1276.Spi.Nss.pin = sx1276_settings->spi.nss; 217 | SX1276.Reset.pin = sx1276_settings->reset; 218 | SX1276.DIO0.pin = sx1276_settings->dio0; 219 | SX1276.DIO1.pin = sx1276_settings->dio1; 220 | 221 | SX1276IoInit(); 222 | 223 | // check version register 224 | if (SX1276Read(REG_LR_VERSION) != 0x12) { 225 | return -1; 226 | } 227 | 228 | LmHandlerParams.Region = region; 229 | 230 | if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) 231 | { 232 | return -1; 233 | } 234 | 235 | // Set system maximum tolerated rx error in milliseconds 236 | LmHandlerSetSystemMaxRxError( 20 ); 237 | 238 | // The LoRa-Alliance Compliance protocol package should always be 239 | // initialized and activated. 240 | LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); 241 | 242 | return 0; 243 | } 244 | 245 | int lorawan_init_abp(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_abp_settings* abp_settings) 246 | { 247 | AbpSettings = abp_settings; 248 | OtaaSettings = NULL; 249 | 250 | return lorawan_init(sx1276_settings, region); 251 | } 252 | 253 | int lorawan_init_otaa(const struct lorawan_sx1276_settings* sx1276_settings, LoRaMacRegion_t region, const struct lorawan_otaa_settings* otaa_settings) 254 | { 255 | AbpSettings = NULL; 256 | OtaaSettings = otaa_settings; 257 | 258 | return lorawan_init(sx1276_settings, region); 259 | } 260 | 261 | int lorawan_join() 262 | { 263 | LmHandlerJoin( ); 264 | 265 | return 0; 266 | } 267 | 268 | int lorawan_is_joined() 269 | { 270 | return (LmHandlerJoinStatus() == LORAMAC_HANDLER_SET); 271 | } 272 | 273 | int lorawan_process() 274 | { 275 | int sleep = 0; 276 | 277 | // Processes the LoRaMac events 278 | LmHandlerProcess( ); 279 | 280 | CRITICAL_SECTION_BEGIN( ); 281 | if( IsMacProcessPending == 1 ) 282 | { 283 | // Clear flag and prevent MCU to go into low power modes. 284 | IsMacProcessPending = 0; 285 | } 286 | else 287 | { 288 | // The MCU wakes up through events 289 | sleep = 1; 290 | } 291 | CRITICAL_SECTION_END( ); 292 | 293 | return sleep; 294 | } 295 | 296 | int lorawan_process_timeout_ms(uint32_t timeout_ms) 297 | { 298 | absolute_time_t timeout_time = make_timeout_time_ms(timeout_ms); 299 | 300 | bool joined = lorawan_is_joined(); 301 | 302 | do { 303 | lorawan_process(); 304 | 305 | if (AppRxData.Port) { 306 | return 0; 307 | } else if (joined != lorawan_is_joined()) { 308 | return 0; 309 | } 310 | } while (!best_effort_wfe_or_timeout(timeout_time)); 311 | 312 | return 1; // timed out 313 | } 314 | 315 | int lorawan_send_unconfirmed(const void* data, uint8_t data_len, uint8_t app_port) 316 | { 317 | LmHandlerAppData_t appData; 318 | 319 | appData.Port = app_port; 320 | appData.BufferSize = data_len; 321 | appData.Buffer = (uint8_t*)data; 322 | 323 | if (LmHandlerSend(&appData, LORAMAC_HANDLER_UNCONFIRMED_MSG) != LORAMAC_HANDLER_SUCCESS) { 324 | return -1; 325 | } 326 | 327 | return 0; 328 | } 329 | 330 | int lorawan_receive(void* data, uint8_t data_len, uint8_t* app_port) 331 | { 332 | *app_port = AppRxData.Port; 333 | if (*app_port == 0) { 334 | return -1; 335 | } 336 | 337 | int receive_length = AppRxData.BufferSize; 338 | 339 | if (data_len < receive_length) { 340 | receive_length = data_len; 341 | } 342 | 343 | memcpy(data, AppRxData.Buffer, receive_length); 344 | AppRxData.Port = 0; 345 | 346 | return receive_length; 347 | } 348 | 349 | void lorawan_debug(bool debug) 350 | { 351 | Debug = debug; 352 | } 353 | 354 | int lorawan_erase_nvm() 355 | { 356 | if (!NvmDataMgmtFactoryReset()) { 357 | return -1; 358 | } 359 | 360 | EepromMcuFlush(); 361 | 362 | return 0; 363 | } 364 | 365 | static void OnMacProcessNotify( void ) 366 | { 367 | IsMacProcessPending = 1; 368 | } 369 | 370 | static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) 371 | { 372 | if (Debug) { 373 | DisplayNvmDataChange( state, size ); 374 | } 375 | 376 | EepromMcuFlush(); 377 | } 378 | 379 | static void OnNetworkParametersChange( CommissioningParams_t* params ) 380 | { 381 | MibRequestConfirm_t mibReq; 382 | 383 | const char* device_eui = NULL; 384 | const char* app_eui = NULL; 385 | const char* device_address = NULL; 386 | const char* app_key = NULL; 387 | const char* app_session_key = NULL; 388 | const char* network_session_key = NULL; 389 | const char* channel_mask = NULL; 390 | 391 | if (OtaaSettings != NULL) { 392 | params->IsOtaaActivation = 1; 393 | 394 | device_eui = OtaaSettings->device_eui; 395 | app_eui = OtaaSettings->app_eui; 396 | app_key = OtaaSettings->app_key; 397 | channel_mask = OtaaSettings->channel_mask; 398 | } 399 | 400 | if (AbpSettings != NULL) { 401 | params->IsOtaaActivation = 0; 402 | 403 | device_address = AbpSettings->device_address; 404 | app_session_key = AbpSettings->app_session_key; 405 | network_session_key = AbpSettings->network_session_key; 406 | channel_mask = AbpSettings->channel_mask; 407 | 408 | // Tell the MAC layer which network server version are we connecting too. 409 | mibReq.Type = MIB_ABP_LORAWAN_VERSION; 410 | mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION; 411 | LoRaMacMibSetRequestConfirm( &mibReq ); 412 | 413 | mibReq.Type = MIB_NET_ID; 414 | mibReq.Param.NetID = LORAWAN_NETWORK_ID; 415 | LoRaMacMibSetRequestConfirm( &mibReq ); 416 | 417 | if (device_address != NULL) { 418 | params->DevAddr = 0; 419 | 420 | for (int i = 0; i < 4; i++) { 421 | int b; 422 | 423 | sscanf(device_address + i * 2, "%2hhx", &b); 424 | 425 | params->DevAddr = (params->DevAddr << 8) | b; 426 | } 427 | } else { 428 | // Random seed initialization 429 | srand1( LmHandlerCallbacks.GetRandomSeed( ) ); 430 | // Choose a random device address 431 | params->DevAddr = randr( 0, 0x01FFFFFF ); 432 | } 433 | 434 | mibReq.Type = MIB_DEV_ADDR; 435 | mibReq.Param.DevAddr = params->DevAddr; 436 | LoRaMacMibSetRequestConfirm( &mibReq ); 437 | } 438 | 439 | if (device_eui != NULL) { 440 | uint8_t deviceEui[8]; 441 | 442 | for (int i = 0; i < 8; i++) { 443 | int b; 444 | 445 | sscanf(device_eui + i * 2, "%2x", &b); 446 | 447 | deviceEui[i] = b; 448 | } 449 | 450 | mibReq.Type = MIB_DEV_EUI; 451 | mibReq.Param.DevEui = deviceEui; 452 | LoRaMacMibSetRequestConfirm( &mibReq ); 453 | memcpy1( params->DevEui, mibReq.Param.DevEui, 8 ); 454 | } 455 | 456 | if (app_eui != NULL) { 457 | uint8_t joinEui[8]; 458 | 459 | for (int i = 0; i < 8; i++) { 460 | int b; 461 | 462 | sscanf(app_eui + i * 2, "%2x", &b); 463 | 464 | joinEui[i] = b; 465 | } 466 | 467 | mibReq.Type = MIB_JOIN_EUI; 468 | mibReq.Param.JoinEui = joinEui; 469 | LoRaMacMibSetRequestConfirm( &mibReq ); 470 | memcpy1( params->JoinEui, mibReq.Param.JoinEui, 8 ); 471 | } 472 | 473 | if (app_key) { 474 | uint8_t appKey[16]; 475 | 476 | for (int i = 0; i < 16; i++) { 477 | int b; 478 | 479 | sscanf(app_key + i * 2, "%2x", &b); 480 | 481 | appKey[i] = b; 482 | } 483 | 484 | mibReq.Type = MIB_APP_KEY; 485 | mibReq.Param.AppKey = appKey; 486 | LoRaMacMibSetRequestConfirm( &mibReq ); 487 | 488 | mibReq.Type = MIB_NWK_KEY; 489 | mibReq.Param.NwkKey = appKey; 490 | LoRaMacMibSetRequestConfirm( &mibReq ); 491 | } 492 | 493 | if (app_session_key) { 494 | uint8_t appSessionKey[16]; 495 | 496 | for (int i = 0; i < 16; i++) { 497 | int b; 498 | 499 | sscanf(app_session_key + i * 2, "%2x", &b); 500 | 501 | appSessionKey[i] = b; 502 | } 503 | 504 | mibReq.Type = MIB_APP_S_KEY; 505 | mibReq.Param.AppSKey = appSessionKey; 506 | LoRaMacMibSetRequestConfirm( &mibReq ); 507 | } 508 | 509 | if (network_session_key) { 510 | uint8_t networkSessionKey[16]; 511 | 512 | for (int i = 0; i < 16; i++) { 513 | int b; 514 | 515 | sscanf(network_session_key + i * 2, "%2x", &b); 516 | 517 | networkSessionKey[i] = b; 518 | } 519 | 520 | mibReq.Type = MIB_F_NWK_S_INT_KEY; 521 | mibReq.Param.FNwkSIntKey = networkSessionKey; 522 | LoRaMacMibSetRequestConfirm( &mibReq ); 523 | 524 | mibReq.Type = MIB_S_NWK_S_INT_KEY; 525 | mibReq.Param.SNwkSIntKey = networkSessionKey; 526 | LoRaMacMibSetRequestConfirm( &mibReq ); 527 | 528 | mibReq.Type = MIB_NWK_S_ENC_KEY; 529 | mibReq.Param.NwkSEncKey = networkSessionKey; 530 | LoRaMacMibSetRequestConfirm( &mibReq ); 531 | } 532 | 533 | if (channel_mask != NULL) { 534 | uint16_t channelMask[6]; 535 | 536 | for (int i = 0; i < 6; i++) { 537 | int b[2]; 538 | 539 | sscanf(channel_mask + i * 4 + 0, "%2x", &b[0]); 540 | sscanf(channel_mask + i * 4 + 2, "%2x", &b[1]); 541 | 542 | channelMask[i] = (b[0] << 8) | b[1]; 543 | } 544 | 545 | mibReq.Type = MIB_CHANNELS_MASK; 546 | mibReq.Param.ChannelsMask = channelMask; 547 | LoRaMacMibSetRequestConfirm( &mibReq ); 548 | 549 | mibReq.Type = MIB_CHANNELS_DEFAULT_MASK; 550 | mibReq.Param.ChannelsDefaultMask = channelMask; 551 | LoRaMacMibSetRequestConfirm( &mibReq ); 552 | } 553 | 554 | if (Debug) { 555 | DisplayNetworkParametersUpdate( params ); 556 | } 557 | } 558 | 559 | static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) 560 | { 561 | if (Debug) { 562 | DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); 563 | } 564 | } 565 | 566 | static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) 567 | { 568 | if (Debug) { 569 | DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); 570 | } 571 | } 572 | 573 | static void OnJoinRequest( LmHandlerJoinParams_t* params ) 574 | { 575 | if (Debug) { 576 | DisplayJoinRequestUpdate( params ); 577 | } 578 | 579 | if( params->Status == LORAMAC_HANDLER_ERROR ) 580 | { 581 | LmHandlerJoin( ); 582 | } 583 | else 584 | { 585 | LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); 586 | } 587 | } 588 | 589 | static void OnTxData( LmHandlerTxParams_t* params ) 590 | { 591 | if (Debug) { 592 | DisplayTxUpdate( params ); 593 | } 594 | } 595 | 596 | static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) 597 | { 598 | if (Debug) { 599 | DisplayRxUpdate( appData, params ); 600 | } 601 | 602 | memcpy(AppRxData.Buffer, appData->Buffer, appData->BufferSize); 603 | AppRxData.BufferSize = appData->BufferSize; 604 | AppRxData.Port = appData->Port; 605 | } 606 | 607 | static void OnClassChange( DeviceClass_t deviceClass ) 608 | { 609 | if (Debug) { 610 | DisplayClassUpdate( deviceClass ); 611 | } 612 | 613 | // Inform the server as soon as possible that the end-device has switched to ClassB 614 | LmHandlerAppData_t appData = 615 | { 616 | .Buffer = NULL, 617 | .BufferSize = 0, 618 | .Port = 0, 619 | }; 620 | LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); 621 | } 622 | 623 | static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) 624 | { 625 | switch( params->State ) 626 | { 627 | case LORAMAC_HANDLER_BEACON_RX: 628 | { 629 | break; 630 | } 631 | case LORAMAC_HANDLER_BEACON_LOST: 632 | case LORAMAC_HANDLER_BEACON_NRX: 633 | { 634 | break; 635 | } 636 | default: 637 | { 638 | break; 639 | } 640 | } 641 | 642 | if (Debug) { 643 | DisplayBeaconUpdate( params ); 644 | } 645 | } 646 | 647 | #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) 648 | static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) 649 | { 650 | 651 | } 652 | #else 653 | static void OnSysTimeUpdate( void ) 654 | { 655 | 656 | } 657 | #endif 658 | 659 | static void OnTxPeriodicityChanged( uint32_t periodicity ) 660 | { 661 | TxPeriodicity = periodicity; 662 | } 663 | 664 | static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) 665 | { 666 | LmHandlerParams.IsTxConfirmed = isTxConfirmed; 667 | } 668 | 669 | static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) 670 | { 671 | LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; 672 | } 673 | --------------------------------------------------------------------------------