2021-12-30 10:58:30 +08:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "generator" content = "rustdoc" >
< title > LoRaWAN on Apache NuttX OS< / title >
<!-- Begin scripts/articles/* - header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
< meta property = "og:title"
content="LoRaWAN on Apache NuttX OS"
data-rh="true">
< meta property = "og:description"
content="Porting Semtech's LoRaWAN Stack to Apache NuttX OS... And testing it on PineDio Stack BL604 RISC-V Board"
data-rh="true">
< meta property = "og:image"
content="https://lupyuen.github.io/images/lorawan3-title.jpg">
< meta property = "og:type"
content="article" data-rh="true">
<!-- End scripts/articles/* - header.html -->
<!-- Begin scripts/rustdoc - header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
< link rel = "alternate" type = "application/rss+xml" title = "RSS Feed for lupyuen" href = "/rss.xml" / >
< link rel = "stylesheet" type = "text/css" href = "../normalize.css" >
< link rel = "stylesheet" type = "text/css" href = "../rustdoc.css" id = "mainThemeStyle" >
< link rel = "stylesheet" type = "text/css" href = "../dark.css" >
< link rel = "stylesheet" type = "text/css" href = "../light.css" id = "themeStyle" >
< link rel = "stylesheet" type = "text/css" href = "../prism.css" >
< script src = "../storage.js" > < / script > < noscript >
< link rel = "stylesheet" href = "../noscript.css" > < / noscript >
< link rel = "shortcut icon" href = "../favicon.ico" >
< style type = "text/css" >
#crate-search {
background-image: url("../down-arrow.svg");
}
< / style >
<!-- End scripts/rustdoc - header.html -->
< / head >
< body class = "rustdoc" >
<!-- [if lte IE 8]>
< div class = "warning" >
This old browser is unsupported and will most likely display funky
things.
< / div >
<![endif]-->
2024-02-17 20:10:07 +08:00
<!-- Begin scripts/rustdoc - before.html: Pre - HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
2021-12-30 10:58:30 +08:00
<!-- Begin Theme Picker -->
< div class = "theme-picker" style = "left: 0" > < button id = "theme-picker" aria-label = "Pick another theme!" > < img src = "../brush.svg"
width="18" alt="Pick another theme!">< / button >
< div id = "theme-choices" > < / div >
< / div >
<!-- Theme Picker -->
<!-- End scripts/rustdoc - before.html -->
< h1 class = "title" > LoRaWAN on Apache NuttX OS< / h1 >
2024-12-04 20:02:50 +08:00
< nav id = "rustdoc" > < ul >
< li > < a href = "#small-steps" title = "Small Steps" > 1 Small Steps< / a > < ul >
< li > < a href = "#lorawan-support" title = "LoRaWAN Support" > 1.1 LoRaWAN Support< / a > < ul > < / ul > < / li >
< li > < a href = "#dependencies" title = "Dependencies" > 1.2 Dependencies< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#lorawan-objective" title = "LoRaWAN Objective" > 2 LoRaWAN Objective< / a > < ul > < / ul > < / li >
< li > < a href = "#download-source-code" title = "Download Source Code" > 3 Download Source Code< / a > < ul > < / ul > < / li >
< li > < a href = "#device-eui-join-eui-and-app-key" title = "Device EUI, Join EUI and App Key" > 4 Device EUI, Join EUI and App Key< / a > < ul >
< li > < a href = "#secure-element" title = "Secure Element" > 4.1 Secure Element< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#lorawan-frequency" title = "LoRaWAN Frequency" > 5 LoRaWAN Frequency< / a > < ul > < / ul > < / li >
< li > < a href = "#build-the-firmware" title = "Build The Firmware" > 6 Build The Firmware< / a > < ul > < / ul > < / li >
< li > < a href = "#run-the-firmware" title = "Run The Firmware" > 7 Run The Firmware< / a > < ul > < / ul > < / li >
< li > < a href = "#join-lorawan-network" title = "Join LoRaWAN Network" > 8 Join LoRaWAN Network< / a > < ul >
< li > < a href = "#check-lorawan-gateway" title = "Check LoRaWAN Gateway" > 8.1 Check LoRaWAN Gateway< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#send-data-to-lorawan" title = "Send Data To LoRaWAN" > 9 Send Data To LoRaWAN< / a > < ul >
< li > < a href = "#message-size" title = "Message Size" > 9.1 Message Size< / a > < ul > < / ul > < / li >
< li > < a href = "#message-interval" title = "Message Interval" > 9.2 Message Interval< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#rerun-the-firmware" title = "Rerun The Firmware" > 10 Rerun The Firmware< / a > < ul >
< li > < a href = "#check-lorawan-gateway-1" title = "Check LoRaWAN Gateway" > 10.1 Check LoRaWAN Gateway< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#lorawan-nonce" title = "LoRaWAN Nonce" > 11 LoRaWAN Nonce< / a > < ul >
< li > < a href = "#strong-random-number-generator" title = "Strong Random Number Generator" > 11.1 Strong Random Number Generator< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#lorawan-event-loop" title = "LoRaWAN Event Loop" > 12 LoRaWAN Event Loop< / a > < ul > < / ul > < / li >
< li > < a href = "#troubleshoot-lorawan" title = "Troubleshoot LoRaWAN" > 13 Troubleshoot LoRaWAN< / a > < ul >
< li > < a href = "#lorawan-is-time-sensitive" title = "LoRaWAN is Time Sensitive" > 13.1 LoRaWAN is Time Sensitive< / a > < ul > < / ul > < / li >
< li > < a href = "#empty-lorawan-message" title = "Empty LoRaWAN Message" > 13.2 Empty LoRaWAN Message< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#spi-with-dma" title = "SPI With DMA" > 14 SPI With DMA< / a > < ul > < / ul > < / li >
< li > < a href = "#whats-next" title = "What’ s Next" > 15 What’ s Next< / a > < ul > < / ul > < / li >
< li > < a href = "#notes" title = "Notes" > 16 Notes< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-posix-timers-and-message-queues" title = "Appendix: POSIX Timers and Message Queues" > 17 Appendix: POSIX Timers and Message Queues< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-random-number-generator-with-entropy-pool" title = "Appendix: Random Number Generator with Entropy Pool" > 18 Appendix: Random Number Generator with Entropy Pool< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-build-flash-and-run-nuttx" title = "Appendix: Build, Flash and Run NuttX" > 19 Appendix: Build, Flash and Run NuttX< / a > < ul >
< li > < a href = "#build-nuttx" title = "Build NuttX" > 19.1 Build NuttX< / a > < ul > < / ul > < / li >
< li > < a href = "#flash-nuttx" title = "Flash NuttX" > 19.2 Flash NuttX< / a > < ul > < / ul > < / li >
< li > < a href = "#run-nuttx" title = "Run NuttX" > 19.3 Run NuttX< / a > < ul > < / ul > < / li > < / ul > < / li > < / ul > < / nav > < p > 📝 < em > 3 Jan 2022< / em > < / p >
2021-12-30 11:49:59 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
< p > < em > PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)< / em > < / p >
< p > Last article we got < strong > LoRa< / strong > (the long-range, low-bandwidth wireless network) running on < a href = "https://lupyuen.github.io/articles/nuttx" > < strong > Apache NuttX OS< / strong > < / a > …< / p >
2021-12-30 10:58:30 +08:00
< ul >
2021-12-30 11:49:59 +08:00
< li > < a href = "https://lupyuen.github.io/articles/sx1262" > < strong > “LoRa SX1262 on Apache NuttX OS”< / strong > < / a > < / li >
2021-12-30 10:58:30 +08:00
< / ul >
2021-12-30 11:49:59 +08:00
< p > Today we shall run < strong > LoRaWAN< / strong > on NuttX OS!< / p >
2021-12-30 11:51:32 +08:00
< p > < em > Why would we need LoRaWAN?< / em > < / p >
2022-01-03 12:23:47 +08:00
< p > LoRa will work perfectly fine for unsecured < strong > Point-to-Point Wireless Communication< / strong > between simple devices.< / p >
2022-01-03 13:02:05 +08:00
< p > But if we’ re building an < strong > IoT Sensor Device< / strong > that will < strong > transmit data packets< / strong > securely to a Local Area Network or to the internet, we need < strong > LoRaWAN< / strong > .< / p >
2021-12-30 10:58:30 +08:00
< p > < a href = "https://makezine.com/2021/05/24/go-long-with-lora-radio/" > (More about LoRaWAN)< / a > < / p >
2022-04-19 12:33:39 +08:00
< p > We shall test LoRaWAN on NuttX with < a href = "https://lupyuen.github.io/articles/pinedio2" > < strong > PineDio Stack BL604 RISC-V Board< / strong > < / a > (pic above) and its onboard Semtech SX1262 Transceiver.< / p >
2022-08-04 12:40:55 +08:00
< p > < a href = "https://twitter.com/4ever_freedom/status/1555048288272932864" > (LoRaWAN on NuttX works OK on < strong > ESP32< / strong > , thanks @4ever_freedom!)< / a > < / p >
2021-12-30 11:49:59 +08:00
< p > < img src = "https://lupyuen.github.io/images/sx1262-library5.jpg" alt = "Porting LoRaWAN to NuttX OS" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "small-steps" > < a class = "doc-anchor" href = "#small-steps" > §< / a > 1 Small Steps< / h1 >
2021-12-30 18:14:03 +08:00
< p > In the last article we created a < strong > LoRa Library for NuttX< / strong > (top right) that works with < strong > Semtech SX1262 Transceiver< / strong > …< / p >
2021-12-30 16:35:12 +08:00
< ul >
2021-12-30 18:14:03 +08:00
< li > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > lupyuen/lora-sx1262 (lorawan branch)< / strong > < / a > < / li >
2021-12-30 16:35:12 +08:00
< / ul >
2021-12-30 18:14:03 +08:00
< p > Today we’ ll create a < strong > LoRaWAN Library for NuttX< / strong > (centre right)…< / p >
2021-12-30 10:58:30 +08:00
< ul >
2021-12-30 18:14:03 +08:00
< li > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > < strong > lupyuen/LoRaMac-node-nuttx< / strong > < / a > < / li >
< / ul >
< p > That’ s a near-identical fork of < strong > Semtech’ s LoRaWAN Stack< / strong > (dated 14 Dec 2021)…< / p >
< ul >
< li > < a href = "https://github.com/Lora-net/LoRaMac-node" > < strong > Lora-net/LoRaMac-node< / strong > < / a > < / li >
2021-12-30 10:58:30 +08:00
< / ul >
2021-12-30 18:29:00 +08:00
< p > We’ ll test with this < strong > LoRaWAN App< / strong > on NuttX…< / p >
< ul >
< li > < a href = "https://github.com/lupyuen/lorawan_test" > < strong > lupyuen/lorawan_test< / strong > < / a > < / li >
< / ul >
2024-03-29 16:55:46 +08:00
< h2 id = "lorawan-support" > < a class = "doc-anchor" href = "#lorawan-support" > §< / a > 1.1 LoRaWAN Support< / h2 >
2021-12-30 18:14:03 +08:00
< p > < em > Why did we fork Semtech’ s LoRaWAN Stack? Why not build it specifically for NuttX?< / em > < / p >
2021-12-30 10:58:30 +08:00
< p > LoRaWAN works < strong > slightly differently across the world regions< / strong > , to comply with Local Wireless Regulations: Radio Frequency, Maximum Airtime (Duty Cycle), < a href = "https://lupyuen.github.io/articles/lorawan#appendix-lora-carrier-sensing" > Listen Before Talk< / a > , …< / p >
< p > Thus we should port < strong > Semtech’ s LoRaWAN Stack< / strong > to NuttX with < strong > minimal changes< / strong > , in case of future updates. (Like for new regions)< / p >
2022-01-03 20:24:14 +08:00
< p > < em > How does our LoRaWAN Library talk to the LoRa SX1262 Library?< / em > < / p >
< p > Our LoRaWAN Library talks through Semtech’ s < strong > Radio Interface< / strong > that’ s exposed by the LoRa SX1262 Library…< / p >
< ul >
2022-01-03 20:25:39 +08:00
< li > < a href = "https://lupyuen.github.io/articles/sx1262#appendix-radio-functions" > < strong > “Radio Functions (LoRa SX1262)”< / strong > < / a > < / li >
2022-01-03 20:24:14 +08:00
< / ul >
2021-12-30 18:14:03 +08:00
< p > < em > How did we create the LoRaWAN Library?< / em > < / p >
< p > We followed the steps below to create < strong > “nuttx/libs/liblorawan”< / strong > by cloning a NuttX Library…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li > < a href = "https://lupyuen.github.io/articles/sx1262#appendix-create-a-nuttx-library" > < strong > “Create a NuttX Library”< / strong > < / a > < / li >
< / ul >
2024-09-11 15:14:35 +08:00
< p > Then we replaced the “liblorawan” folder by a < strong > Git Submodule< / strong > that contains our LoRaWAN code…< / p >
2021-12-30 10:58:30 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > cd nuttx/nuttx/libs
2021-12-30 18:14:03 +08:00
rm -r liblorawan
git rm -r liblorawan
2024-12-04 20:02:50 +08:00
git submodule add https://github.com/lupyuen/LoRaMac-node-nuttx liblorawan< / code > < / pre > < / div >
2022-01-03 20:12:34 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#download-source-code" > (To add the LoRaWAN Library to your NuttX Project, see this)< / a > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "dependencies" > < a class = "doc-anchor" href = "#dependencies" > §< / a > 1.2 Dependencies< / h2 >
2021-12-30 18:14:03 +08:00
< p > Our LoRaWAN Library should work on < strong > any NuttX platform< / strong > (like ESP32), assuming that the following dependencies are installed…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li >
2021-12-30 18:14:03 +08:00
< p > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > lupyuen/lora-sx1262 (lorawan branch)< / strong > < / a > < / p >
< p > LoRa Library for Semtech SX1262 Transceiver< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262" > (See this)< / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/nimble-porting-nuttx" > < strong > lupyuen/nimble-porting-nuttx< / strong > < / a > < / p >
< p > NimBLE Porting Layer multithreading library< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262#multithreading-with-nimble-porting-layer" > (See this)< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
2022-11-30 12:01:12 +08:00
< p > < a href = "https://github.com/lupyuen/nuttx/tree/lorawan/drivers/rf" > < strong > spi_test_driver (/dev/spitest0)< / strong > < / a > < / p >
2021-12-30 18:14:03 +08:00
< p > SPI Test Driver< / p >
< p > < a href = "https://lupyuen.github.io/articles/spi2" > (See this)< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< / ul >
2021-12-30 18:14:03 +08:00
< p > Our LoRa SX1262 Library assumes that the following < strong > NuttX Devices< / strong > are configured…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/gpio0< / strong > : GPIO Input for SX1262 Busy Pin< / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/gpio1< / strong > : GPIO Output for SX1262 Chip Select< / p >
< / li >
< li >
< p > < strong > /dev/gpio2< / strong > : GPIO Interrupt for SX1262 DIO1 Pin< / p >
< / li >
< li >
2021-12-30 20:20:16 +08:00
< p > < strong > /dev/spi0< / strong > : SPI Bus for SX1262< / p >
< / li >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/spitest0< / strong > : SPI Test Driver (see above)< / p >
2021-12-30 10:58:30 +08:00
< / li >
< / ul >
2024-03-29 16:55:46 +08:00
< h1 id = "lorawan-objective" > < a class = "doc-anchor" href = "#lorawan-objective" > §< / a > 2 LoRaWAN Objective< / h1 >
2021-12-31 01:42:31 +08:00
< p > < em > What shall we accomplish with LoRaWAN today?< / em > < / p >
< p > We’ ll do the basic LoRaWAN use case on NuttX…< / p >
< ul >
< li >
2021-12-31 10:02:51 +08:00
< p > Join NuttX to the < strong > LoRaWAN Network< / strong > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > Send a < strong > Data Packet< / strong > from NuttX to LoRaWAN< / p >
< / li >
< / ul >
< p > Which works like this…< / p >
2021-12-31 09:48:18 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow.jpg" alt = "LoRaWAN Use Case" / > < / p >
2021-12-31 01:42:31 +08:00
< ol >
< li >
< p > NuttX sends a < strong > Join Network Request< / strong > to the LoRaWAN Gateway.< / p >
< p > Inside the Join Network Request are…< / p >
2021-12-31 10:02:51 +08:00
< p > < strong > Device EUI:< / strong > Unique ID that’ s assigned to our LoRaWAN Device< / p >
< p > < strong > Join EUI:< / strong > Identifies the LoRaWAN Network that we’ re joining< / p >
2021-12-31 10:24:15 +08:00
< p > < strong > Nonce:< / strong > Non-repeating number, to prevent < a href = "https://en.wikipedia.org/wiki/Replay_attack" > Replay Attacks< / a > < / p >
2022-01-01 09:56:22 +08:00
< p > < em > (EUI sounds like Durian on Century Egg… But it actually means Extended Unique Identifier)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > LoRaWAN Gateway returns a < strong > Join Network Response< / strong > < / p >
2021-12-31 14:41:03 +08:00
< p > < em > (Which contains the Device Address)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > NuttX sends a < strong > Data Packet< / strong > to the LoRaWAN Network< / p >
2021-12-31 14:41:03 +08:00
< p > < em > (Which has the Device Address and Payload “Hi NuttX”)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > NuttX uses an < strong > App Key< / strong > to sign the Join Network Request and the Data Packet< / p >
2021-12-31 14:41:03 +08:00
< p > < em > (App Key is stored inside NuttX, never exposed over the airwaves)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< / ol >
2021-12-31 14:27:01 +08:00
< p > In a while we’ ll set the Device EUI, Join EUI and App Key in our code.< / p >
2024-03-29 16:55:46 +08:00
< h1 id = "download-source-code" > < a class = "doc-anchor" href = "#download-source-code" > §< / a > 3 Download Source Code< / h1 >
2021-12-31 14:27:01 +08:00
< p > To run LoRaWAN on NuttX, download the modified source code for < strong > NuttX OS and NuttX Apps< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > mkdir nuttx
cd nuttx
2022-11-30 12:01:12 +08:00
git clone --recursive --branch lorawan https://github.com/lupyuen/nuttx nuttx
2024-12-04 20:02:50 +08:00
git clone --recursive --branch lorawan https://github.com/lupyuen/nuttx-apps apps< / code > < / pre > < / div >
2021-12-31 14:27:01 +08:00
< p > Or if we prefer to < strong > add the LoRaWAN Library< / strong > to our NuttX Project, follow these instructions…< / p >
2022-04-11 08:36:32 +08:00
< p > < a href = "https://lupyuen.github.io/articles/pinedio2#appendix-bundled-features" > (< strong > For PineDio Stack BL604:< / strong > The features below are already preinstalled)< / a > < / p >
2021-12-31 14:27:01 +08:00
< ol >
< li >
2022-11-30 12:01:12 +08:00
< p > < a href = "https://github.com/lupyuen/nuttx/tree/lorawan/drivers/rf" > < strong > “Install SPI Test Driver”< / strong > < / a > < / p >
2021-12-31 14:27:01 +08:00
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/nimble-porting-nuttx" > < strong > “Install NimBLE Porting Layer”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > “Install LoRa SX1262 Library”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > < strong > “Install LoRaWAN Library”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/lorawan_test" > < strong > “Install LoRaWAN Test App”< / strong > < / a > < / p >
< / li >
2022-01-03 13:02:05 +08:00
< li >
< p > Disable the Assertion Check for < strong > GPIO Pin Type< / strong > …< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262#appendix-gpio-pin-type-issue" > < strong > “GPIO Pin Type Issue”< / strong > < / a > < / p >
< / li >
2021-12-31 14:27:01 +08:00
< / ol >
2021-12-31 16:24:13 +08:00
< p > Let’ s configure our LoRaWAN code.< / p >
2021-12-31 15:33:02 +08:00
< p > < img src = "https://lupyuen.github.io/images/wisgate-app2.png" alt = "Device EUI from ChirpStack" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "device-eui-join-eui-and-app-key" > < a class = "doc-anchor" href = "#device-eui-join-eui-and-app-key" > §< / a > 4 Device EUI, Join EUI and App Key< / h1 >
2021-12-31 14:27:01 +08:00
< p > < em > Where do we get the Device EUI, Join EUI and App Key?< / em > < / p >
2021-12-31 15:33:02 +08:00
< p > We get the LoRaWAN Settings from our < strong > LoRaWAN Gateway< / strong > , like ChirpStack (pic above)…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/wisgate#lorawan-application" > < strong > “LoRaWAN Application (ChirpStack)”< / strong > < / a > < / li >
< / ul >
< p > < em > How do we set the Device EUI, Join EUI and App Key in our code?< / em > < / p >
< p > Edit the file…< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > nuttx/libs/liblorawan/src/peripherals/soft-se/se-identity.h< / code > < / pre > < / div >
2021-12-31 17:09:16 +08:00
< p > Look for these lines in < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/peripherals/soft-se/se-identity.h#L65-L79" > < strong > se-identity.h< / strong > < / a > < / p >
2021-12-31 15:33:02 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > /*!
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically set with a value provided by MCU platform
*/
#define STATIC_DEVICE_EUI 1
/*!
* end-device IEEE EUI (big endian)
*/
#define LORAWAN_DEVICE_EUI { 0x4b, 0xc1, 0x5e, 0xe7, 0x37, 0x7b, 0xb1, 0x5b }
/*!
* App/Join server IEEE EUI (big endian)
*/
2024-12-04 20:02:50 +08:00
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }< / code > < / pre > < / div >
2021-12-31 15:33:02 +08:00
< ul >
< li >
< p > < strong > STATIC_DEVICE_EUI:< / strong > Must be < code > 1< / code > < / p >
< / li >
< li >
2022-01-03 09:31:52 +08:00
< p > < strong > LORAWAN_DEVICE_EUI:< / strong > Change this to our < strong > LoRaWAN Device EUI< / strong > (MSB First)< / p >
2021-12-31 17:46:40 +08:00
< p > For ChirpStack: Copy from “Applications → app → Device EUI”< / p >
2021-12-31 15:33:02 +08:00
< / li >
< li >
2022-01-03 09:31:52 +08:00
< p > < strong > LORAWAN_JOIN_EUI:< / strong > Change this to our < strong > LoRaWAN Join EUI< / strong > (MSB First)< / p >
2021-12-31 16:19:00 +08:00
< p > For ChirpStack: Join EUI is not needed, we leave it as zeroes< / p >
2021-12-31 15:33:02 +08:00
< / li >
< / ul >
2021-12-31 15:55:25 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-secure1.png" alt = "Device EUI and Join EUI" / > < / p >
2021-12-31 17:09:16 +08:00
< p > Next find this in the same file < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/peripherals/soft-se/se-identity.h#L98-L115" > < strong > se-identity.h< / strong > < / a > < / p >
2021-12-31 15:33:02 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > #define SOFT_SE_KEY_LIST \
{ \
{ \
/*! \
* Application root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
*/ \
.KeyID = APP_KEY, \
.KeyValue = { 0xaa, 0xff, 0xad, 0x5c, 0x7e, 0x87, 0xf6, 0x4d, 0xe3, 0xf0, 0x87, 0x32, 0xfc, 0x1d, 0xd2, 0x5d }, \
}, \
{ \
/*! \
* Network root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
*/ \
.KeyID = NWK_KEY, \
.KeyValue = { 0xaa, 0xff, 0xad, 0x5c, 0x7e, 0x87, 0xf6, 0x4d, 0xe3, 0xf0, 0x87, 0x32, 0xfc, 0x1d, 0xd2, 0x5d }, \
2024-12-04 20:02:50 +08:00
}, \< / code > < / pre > < / div >
2021-12-31 15:33:02 +08:00
< ul >
< li >
2022-01-03 09:31:52 +08:00
< p > < strong > APP_KEY:< / strong > Change this to our < strong > LoRaWAN App Key< / strong > (MSB First)< / p >
2021-12-31 17:46:40 +08:00
< p > For ChirpStack: Copy from “Applications → app → Devices → device_otaa_class_a → Keys (OTAA) → Application Key”< / p >
2021-12-31 15:33:02 +08:00
< / li >
< li >
< p > < strong > NWK_KEY:< / strong > Change this to our < strong > LoRaWAN App Key< / strong > < / p >
< p > (Same as < strong > APP_KEY< / strong > )< / p >
< / li >
< / ul >
2021-12-31 15:55:25 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-secure2a.png" alt = "App Key" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "secure-element" > < a class = "doc-anchor" href = "#secure-element" > §< / a > 4.1 Secure Element< / h2 >
2021-12-31 15:55:25 +08:00
< p > < em > What’ s “soft-se”? Why are our LoRaWAN Settings there?< / em > < / p >
2021-12-31 18:21:35 +08:00
< p > For LoRaWAN Devices that are designed to be < strong > super secure< / strong > , they < strong > don’ t expose the LoRaWAN App Key< / strong > in the firmware code…< / p >
2021-12-31 16:19:00 +08:00
< p > Instead they store the App Key in the < a href = "https://encyclopedia.kaspersky.com/glossary/secure-element/" > < strong > Secure Element< / strong > < / a > hardware.< / p >
2021-12-31 17:46:40 +08:00
< p > Our LoRaWAN Library supports two kinds of Secure Elements: < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/atecc608a-tnglora-se" > < strong > Microchip ATECC608A< / strong > < / a > and < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/lr1110-se" > < strong > Semtech LR1110< / strong > < / a > < / p >
2021-12-31 16:19:00 +08:00
< p > < em > But our NuttX Device doesn’ t have a Secure Element right?< / em > < / p >
< p > That’ s why we define the App Key in the < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/soft-se" > < strong > “Software Secure Element (soft-se)”< / strong > < / a > that simulates a Hardware Secure Element… Minus the actual hardware security.< / p >
2021-12-31 18:21:35 +08:00
< p > Our App Key will be exposed if somebody dumps the firmware for our NuttX Device. But it’ s probably OK during development.< / p >
2024-03-29 16:55:46 +08:00
< h1 id = "lorawan-frequency" > < a class = "doc-anchor" href = "#lorawan-frequency" > §< / a > 5 LoRaWAN Frequency< / h1 >
2021-12-31 17:46:40 +08:00
< p > Let’ s set the LoRaWAN Frequency…< / p >
2021-12-31 17:09:16 +08:00
< ol >
< li >
< p > Find the < strong > LoRaWAN Frequency< / strong > for our region…< / p >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html" > < strong > “Frequency Plans by Country”< / strong > < / a > < / p >
< / li >
< li >
< p > Edit our < strong > LoRaWAN Test App< / strong > …< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > apps/examples/lorawan_test/lorawan_test_main.c< / code > < / pre > < / div > < / li >
2021-12-31 17:09:16 +08:00
< li >
< p > Find this in < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L34-L40" > < strong > lorawan_test_main.c< / strong > < / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > #ifndef ACTIVE_REGION
#warning " No active region defined, LORAMAC_REGION_AS923 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_AS923
2024-12-04 20:02:50 +08:00
#endif< / code > < / pre > < / div > < / li >
2021-12-31 17:09:16 +08:00
< li >
< p > Change < strong > AS923< / strong > (both occurrences) to our LoRaWAN Frequency…< / p >
< p > < strong > US915< / strong > , < strong > CN779< / strong > , < strong > EU433< / strong > , < strong > AU915< / strong > , < strong > AS923< / strong > , < strong > CN470< / strong > , < strong > KR920< / strong > , < strong > IN865< / strong > or < strong > RU864< / strong > < / p >
< / li >
< li >
2021-12-31 17:52:11 +08:00
< p > Do the same for the LoRaMAC Handler: < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/apps/LoRaMac/common/LmHandler/LmHandler.c#L41-L47" > < strong > LmHandler.c< / strong > < / a > < / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > nuttx/libs/liblorawan/src/apps/LoRaMac/common/LmHandler/LmHandler.c< / code > < / pre > < / div >
2021-12-31 17:09:16 +08:00
< p > (We ought to define this parameter in Kconfig instead)< / p >
< / li >
< / ol >
2024-03-29 16:55:46 +08:00
< h1 id = "build-the-firmware" > < a class = "doc-anchor" href = "#build-the-firmware" > §< / a > 6 Build The Firmware< / h1 >
2021-12-31 19:09:25 +08:00
< p > Let’ s build the NuttX Firmware that contains our < strong > LoRaWAN Library< / strong > …< / p >
< ol >
< li >
< p > Install the build prerequisites…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#install-prerequisites" > < strong > “Install Prerequisites”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 10:27:28 +08:00
< p > Assume that we have downloaded the < strong > NuttX Source Code< / strong > and configured the < strong > LoRaWAN Settings< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#download-source-code" > < strong > “Download Source Code”< / strong > < / a > < / p >
2022-01-01 10:27:28 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#device-eui-join-eui-and-app-key" > < strong > “Device EUI, Join EUI and App Key”< / strong > < / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#lorawan-frequency" > < strong > “LoRaWAN Frequency”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:14:14 +08:00
< p > Edit the < strong > Pin Definitions< / strong > …< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ## For BL602 and BL604:
2022-01-01 12:14:14 +08:00
nuttx/boards/risc-v/bl602/bl602evb/include/board.h
2023-01-13 07:19:30 +08:00
## For ESP32: Change " esp32-devkitc" to our ESP32 board
2024-12-04 20:02:50 +08:00
nuttx/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c< / code > < / pre > < / div >
2022-11-30 12:01:12 +08:00
< p > Check that the < strong > Semtech SX1262 Pins< / strong > are configured correctly in < a href = "https://github.com/lupyuen/nuttx/blob/lorawan/boards/risc-v/bl602/bl602evb/include/board.h#L36-L95" > < strong > board.h< / strong > < / a > or < a href = "https://github.com/lupyuen/nuttx/blob/lorawan/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c#L43-L67" > < strong > esp32_gpio.c< / strong > < / a > …< / p >
2022-05-01 12:21:41 +08:00
< p > < a href = "https://lupyuen.github.io/articles/expander#pin-functions" > (Which pins can be used? See this)< / a > < / p >
2022-01-01 12:14:14 +08:00
< p > < a href = "https://lupyuen.github.io/articles/sx1262#connect-sx1262-transceiver" > < strong > “Connect SX1262 Transceiver”< / strong > < / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > Configure the build…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > cd nuttx
2023-01-13 07:19:30 +08:00
## For BL602: Configure the build for BL602
2021-12-31 19:09:25 +08:00
./tools/configure.sh bl602evb:nsh
2023-01-13 07:19:30 +08:00
## For PineDio Stack BL604: Configure the build for BL604
2022-04-11 08:42:04 +08:00
./tools/configure.sh bl602evb:pinedio
2023-01-13 07:19:30 +08:00
## For ESP32: Configure the build for ESP32.
## TODO: Change " esp32-devkitc" to our ESP32 board.
2021-12-31 19:09:25 +08:00
./tools/configure.sh esp32-devkitc:nsh
2023-01-13 07:19:30 +08:00
## Edit the Build Config
2024-12-04 20:02:50 +08:00
make menuconfig < / code > < / pre > < / div > < / li >
2021-12-31 19:09:25 +08:00
< li >
< p > Enable the < strong > GPIO Driver< / strong > in menuconfig…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#enable-gpio-driver" > < strong > “Enable GPIO Driver”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:16:40 +08:00
< p > Enable the < strong > SPI Peripheral< / strong > , < strong > SPI Character Driver< / strong > and < strong > SPI Test Driver< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/spi2#enable-spi" > < strong > “Enable SPI”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:16:40 +08:00
< p > Enable < strong > GPIO and SPI Logging< / strong > for easier troubleshooting, but uncheck < strong > “Enable Info Debug Output”< / strong > , < strong > “GPIO Info Output”< / strong > and < strong > “SPI Info Output”< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/spi2#enable-logging" > < strong > “Enable Logging”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 09:47:11 +08:00
< p > Enable < strong > Stack Backtrace< / strong > for easier troubleshooting…< / p >
< p > Check the box for < strong > “RTOS Features”< / strong > → < strong > “Stack Backtrace”< / strong > < / p >
< p > < a href = "https://lupyuen.github.io/images/lorawan3-config4.png" > (See this)< / a > < / p >
< / li >
< li >
2022-01-01 10:23:28 +08:00
< p > Enable < strong > POSIX Timers and Message Queues< / strong > (for NimBLE Porting Layer)…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-posix-timers-and-message-queues" > < strong > “POSIX Timers and Message Queues”< / strong > < / a > < / p >
2021-12-31 19:55:05 +08:00
< / li >
< li >
2022-01-01 10:23:28 +08:00
< p > Enable < strong > Random Number Generator with Entropy Pool< / strong > (for LoRaWAN Nonces)…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-random-number-generator-with-entropy-pool" > < strong > “Random Number Generator with Entropy Pool”< / strong > < / a > < / p >
< p > (We’ ll talk about this in a while)< / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > Click < strong > “Library Routines”< / strong > and enable the following libraries…< / p >
< p > < strong > “LoRaWAN Library”< / strong > < / p >
< p > < strong > “NimBLE Porting Layer”< / strong > < / p >
< p > < strong > “Semtech SX1262 Library”< / strong > < / p >
< / li >
< li >
< p > Enable our < strong > LoRaWAN Test App< / strong > …< / p >
< p > Check the box for < strong > “Application Configuration”< / strong > → < strong > “Examples”< / strong > → < strong > “LoRaWAN Test App”< / strong > < / p >
< / li >
< li >
< p > Save the configuration and exit menuconfig< / p >
2022-01-01 12:16:40 +08:00
< p > < a href = "https://gist.github.com/lupyuen/d0487cda965f72ed99631d168ea4f5c8" > (See the .config for BL602 and BL604)< / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
2022-01-04 09:25:37 +08:00
< p > < strong > For ESP32:< / strong > Edit the function < strong > esp32_bringup< / strong > in this file…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ## Change " esp32-devkitc" to our ESP32 board
2024-12-04 20:02:50 +08:00
nuttx/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c< / code > < / pre > < / div >
2022-01-04 09:25:37 +08:00
< p > And call < strong > spi_test_driver_register< / strong > to register our SPI Test Driver.< / p >
< p > < a href = "https://lupyuen.github.io/articles/spi2#register-device-driver" > (See this)< / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > Build, flash and run the NuttX Firmware on BL602 or ESP32…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-build-flash-and-run-nuttx" > < strong > “Build, Flash and Run NuttX”< / strong > < / a > < / p >
< / li >
< / ol >
2022-01-01 13:38:19 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx3.png" alt = "Our NuttX Device successfully joins the LoRaWAN Network" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (Source)< / a > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "run-the-firmware" > < a class = "doc-anchor" href = "#run-the-firmware" > §< / a > 7 Run The Firmware< / h1 >
2022-01-01 13:38:19 +08:00
< p > We’ re ready to run the NuttX Firmware and test our < strong > LoRaWAN Library< / strong > !< / p >
2021-12-31 19:09:25 +08:00
< ol >
< li >
2022-01-01 13:38:19 +08:00
< p > In the NuttX Shell, list the < strong > NuttX Devices< / strong > …< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > ls /dev< / code > < / pre > < / div > < / li >
2021-12-31 19:55:05 +08:00
< li >
< p > We should see…< / p >
2022-01-01 13:38:19 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > /dev:
gpio0
gpio1
gpio2
spi0
spitest0
urandom
2024-12-04 20:02:50 +08:00
...< / code > < / pre > < / div >
2022-01-01 13:38:19 +08:00
< p > Our SPI Test Driver appears as < strong > “/dev/spitest0”< / strong > < / p >
< p > The SX1262 Pins for Busy, Chip Select and DIO1 should appear as < strong > “/dev/gpio0”< / strong > (GPIO Input), < strong > “gpio1”< / strong > (GPIO Output) and < strong > “gpio2”< / strong > (GPIO Interrupt) respectively.< / p >
< p > The Random Number Generator (with Entropy Pool) appears as < strong > “/dev/urandom”< / strong > < / p >
< / li >
< li >
< p > In the NuttX Shell, run our < strong > LoRaWAN Test App< / strong > …< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > lorawan_test< / code > < / pre > < / div >
2022-01-01 13:38:19 +08:00
< p > Our app sends a < strong > Join Network Request< / strong > to the LoRaWAN Gateway…< / p >
2022-01-01 20:36:08 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > RadioSetPublicNetwork: public syncword=3444
DevEui : 4B-C1-5E-E7-37-7B-B1-5B
JoinEui : 00-00-00-00-00-00-00-00
Pin : 00-00-00-00
2023-01-13 07:19:30 +08:00
### =========== MLME-Request ============ ##
### MLME_JOIN ##
### ===================================== ##
2024-12-04 20:02:50 +08:00
STATUS : OK< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > (Which contains the Device EUI and Join EUI that we have configured earlier)< / p >
< / li >
2022-01-01 13:38:19 +08:00
< li >
< p > A few seconds later we should see the < strong > Join Network Response< / strong > from the LoRaWAN Gateway…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ### =========== MLME-Confirm ============ ##
2022-01-01 13:38:19 +08:00
STATUS : OK
2023-01-13 07:19:30 +08:00
### =========== JOINED ============ ##
2022-01-01 13:38:19 +08:00
OTAA
DevAddr : 01DA9790
2024-12-04 20:02:50 +08:00
DATA RATE : DR_2< / code > < / pre > < / div >
2022-01-01 13:38:19 +08:00
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< p > Congratulations our NuttX Device has successfully joined the LoRaWAN Network!< / p >
< / li >
< li >
< p > If we see this instead…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ### =========== MLME-Confirm ============ ##
2024-12-04 20:02:50 +08:00
STATUS : Rx 1 timeout< / code > < / pre > < / div >
2022-01-01 13:38:19 +08:00
< p > < a href = "https://gist.github.com/lupyuen/007788b9ea3974b127f6260bf57f5d8b" > (See the Output Log)< / a > < / p >
< p > Our Join Network Request has failed.< / p >
< p > Check the next section for troubleshooting tips.< / p >
< / li >
< li >
2022-01-01 19:06:48 +08:00
< p > Our LoRaWAN Test App continues to < strong > transmit Data Packets< / strong > . But we’ ll cover this later…< / p >
2022-01-01 13:38:19 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
PrepareTxFrame: status=0, maxSize=11, currentSize=11
2023-01-13 07:19:30 +08:00
### =========== MCPS-Request ============ ##
### MCPS_UNCONFIRMED ##
### ===================================== ##
2022-01-01 13:38:19 +08:00
STATUS : OK
2024-12-04 20:02:50 +08:00
PrepareTxFrame: Transmit OK< / code > < / pre > < / div >
2022-01-01 13:38:19 +08:00
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
2022-01-01 19:06:48 +08:00
< p > Let’ s find out how our LoRaWAN Test App joins the LoRaWAN Network.< / p >
2021-12-31 19:09:25 +08:00
< / li >
< / ol >
2022-01-01 19:06:48 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow2.jpg" alt = "Join LoRaWAN Network" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "join-lorawan-network" > < a class = "doc-anchor" href = "#join-lorawan-network" > §< / a > 8 Join LoRaWAN Network< / h1 >
2022-01-01 14:17:40 +08:00
< p > < em > How do we join the LoRaWAN Network in our NuttX App?< / em > < / p >
2022-01-01 19:06:48 +08:00
< p > Let’ s dive into the code for our < strong > LoRaWAN Test App< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L260-L303" > lorawan_test_main.c< / a > < / p >
2022-01-01 14:17:40 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > int main(int argc, FAR char *argv[]) {
2022-01-01 14:22:19 +08:00
// Compute the interval between transmissions based on Duty Cycle
2024-12-04 20:02:50 +08:00
TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > Our app begins by computing the < strong > Time Interval Between Transmissions< / strong > of our Data Packets.< / p >
< p > (More about this later)< / p >
< p > Next it calls < strong > LmHandlerInit< / strong > to initialise the LoRaWAN Library…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Init LoRaWAN
2022-01-02 12:25:44 +08:00
if ( LmHandlerInit(
& LmHandlerCallbacks, // Callback Functions
& LmHandlerParams // LoRaWAN Parameters
) != LORAMAC_HANDLER_SUCCESS ) {
2022-01-01 14:22:19 +08:00
printf( " LoRaMac wasn' t properly initialized\n" );
while ( 1 ) {} // Fatal error, endless loop.
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > (Functions named < strong > “Lm…”< / strong > come from our LoRaWAN Library)< / p >
2022-01-01 19:06:48 +08:00
< p > We set load the < strong > LoRa Alliance Compliance Protocol Packages< / strong > …< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Set system maximum tolerated rx error in milliseconds
LmHandlerSetSystemMaxRxError( 20 );
2022-01-01 14:17:40 +08:00
2022-01-01 14:22:19 +08:00
// 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 );
2024-12-04 20:02:50 +08:00
LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, & FragmentationParams );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > Below is the code that sends the < strong > Join Network Request< / strong > to the LoRaWAN Gateway: < strong > LmHandlerJoin< / strong > …< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Join the LoRaWAN Network
2024-12-04 20:02:50 +08:00
LmHandlerJoin( );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > We start the < strong > Transmit Timer< / strong > that will schedule the transmission of Data Packets (right after we have joined the LoRaWAN Network)…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Set the Transmit Timer
2024-12-04 20:02:50 +08:00
StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > At this point we haven’ t actually joined the LoRaWAN Network yet.< / p >
< p > This happens in the < strong > LoRaWAN Event Loop< / strong > that will handle the < strong > Join Network Response< / strong > received from the LoRaWAN Gateway…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Handle LoRaWAN Events
handle_event_queue( NULL ); // Never returns
return 0;
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > (We’ ll talk about the LoRaWAN Event Loop later)< / p >
< p > Let’ s check the logs on our LoRaWAN Gateway. (RAKwireless WisGate, the black box below)< / p >
2021-12-31 18:21:35 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "check-lorawan-gateway" > < a class = "doc-anchor" href = "#check-lorawan-gateway" > §< / a > 8.1 Check LoRaWAN Gateway< / h2 >
2022-01-01 20:36:08 +08:00
< p > To inspect the Join Network Request on our < strong > LoRaWAN Gateway< / strong > (ChirpStack), click…< / p >
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > LoRaWAN Frames< / strong > < / p >
< p > Restart our NuttX Device and the LoRaWAN Test App…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/lorawan3#run-the-firmware" > < strong > “Run The Firmware”< / strong > < / a > < / li >
< / ul >
< p > The < strong > Join Network Request< / strong > appears in ChirpStack…< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack.png" alt = "Join Network Request" / > < / p >
< p > (Yep that’ s the Device EUI and Join EUI that we have configured earlier)< / p >
< p > Followed by the < strong > Join Accept Response< / strong > …< / p >
2022-01-02 08:00:58 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack7.png" alt = "Join Accept Response" / > < / p >
2022-01-01 20:36:08 +08:00
< p > The Join Network Request / Response also appears in ChirpStack at…< / p >
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > Device Data< / strong > < / p >
2022-01-02 16:07:42 +08:00
< p > Like so (“Join”)…< / p >
2022-01-02 08:00:58 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack10.png" alt = "Join Accept Response" / > < / p >
2022-01-01 20:36:08 +08:00
< p > < em > What if we don’ t see the Join Network Request or the Join Accept Response?< / em > < / p >
< p > Check the < strong > “Troubleshoot LoRaWAN”< / strong > section below for troubleshooting tips.< / p >
2024-03-29 16:55:46 +08:00
< h1 id = "send-data-to-lorawan" > < a class = "doc-anchor" href = "#send-data-to-lorawan" > §< / a > 9 Send Data To LoRaWAN< / h1 >
2022-01-02 12:25:44 +08:00
< p > Now that we’ ve joined the LoRaWAN Network, we’ re ready to < strong > send Data Packets< / strong > to LoRaWAN!< / p >
< p > < strong > PrepareTxFrame< / strong > is called by our LoRaWAN Event Loop to send a Data Packet when the < strong > Transmit Timer< / strong > expires: < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L305-L336" > lorawan_test_main.c< / a > < / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Prepare the payload of a Data Packet transmit it
static void PrepareTxFrame( void ) {
2022-01-02 12:25:44 +08:00
2022-01-02 09:32:47 +08:00
// If we haven' t joined the LoRaWAN Network, try again later
2024-12-04 20:02:50 +08:00
if (LmHandlerIsBusy()) { puts(" PrepareTxFrame: Busy" ); return; }< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > If we haven’ t joined a LoRaWAN Network yet, this function will return. (And we’ ll try again later)< / p >
< p > Assuming all is hunky dory, we proceed to transmit a < strong > 9-byte message< / strong > (including terminating null)…< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Send a message to LoRaWAN
const char msg[] = " Hi NuttX" ;
2024-12-04 20:02:50 +08:00
printf(" PrepareTxFrame: Transmit to LoRaWAN: %s (%d bytes)\n" , msg, sizeof(msg));< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > We copy the message to the < strong > Transmit Buffer< / strong > (max 242 bytes) and create a < strong > Transmit Request< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Compose the transmit request
2022-01-02 12:25:44 +08:00
assert(sizeof(msg) < = sizeof(AppDataBuffer));
2022-01-02 09:32:47 +08:00
memcpy(AppDataBuffer, msg, sizeof(msg));
2022-01-02 12:25:44 +08:00
LmHandlerAppData_t appData = { // Transmit Request contains...
.Buffer = AppDataBuffer, // Transmit Buffer
.BufferSize = sizeof(msg), // Size of Transmit Buffer
.Port = 1, // Port Number: 1 to 223
2024-12-04 20:02:50 +08:00
};< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > Next we < strong > validate the Message Size< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Validate the message size and check if it can be transmitted
LoRaMacTxInfo_t txInfo;
2022-01-02 12:25:44 +08:00
LoRaMacStatus_t status = LoRaMacQueryTxPossible(
appData.BufferSize, // Message size
& txInfo // Returns max message size
);
2022-01-02 09:32:47 +08:00
printf(" PrepareTxFrame: status=%d, maxSize=%d, currentSize=%d\n" , status, txInfo.MaxPossibleApplicationDataSize, txInfo.CurrentPossiblePayloadSize);
2024-12-04 20:02:50 +08:00
assert(status == LORAMAC_STATUS_OK);< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > (What’ s the Maximum Message Size? We’ ll discuss in a while)< / p >
< p > Finally we < strong > transmit the message< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Transmit the message
2022-01-02 12:25:44 +08:00
LmHandlerErrorStatus_t sendStatus = LmHandlerSend(
& appData, // Transmit Request
LmHandlerParams.IsTxConfirmed // 0 for Unconfirmed
);
2022-01-02 09:32:47 +08:00
assert(sendStatus == LORAMAC_HANDLER_SUCCESS);
puts(" PrepareTxFrame: Transmit OK" );
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > < em > Why is our Data Packet marked Unconfirmed?< / em > < / p >
< p > Our Data Packet is marked Unconfirmed because we < strong > don’ t expect an acknowledgement< / strong > from the LoRaWAN Gateway.< / p >
2024-09-11 15:14:35 +08:00
< p > This is the typical mode for < strong > IoT Sensor Devices< / strong > , which don’ t handle acknowledgements to conserve battery power.< / p >
2022-01-02 12:25:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx6.png" alt = "Sending a LoRaWAN Data Packet" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "message-size" > < a class = "doc-anchor" href = "#message-size" > §< / a > 9.1 Message Size< / h2 >
2022-01-02 13:56:23 +08:00
< p > < em > What’ s the Maximum Message Size?< / em > < / p >
2022-01-02 13:37:59 +08:00
< p > The < strong > Maximum Message (Payload) Size< / strong > depends on…< / p >
< ul >
< li >
< p > < strong > LoRaWAN Data Rate< / strong > (like Data Rate 2 or 3)< / p >
< / li >
< li >
< p > < strong > LoRaWAN Region< / strong > (AS923 for Asia, AU915 for Australia / Brazil / New Zealand, EU868 for Europe, US915 for US, …)< / p >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html" > (See this)< / a > < / p >
< / li >
< / ul >
< p > Our LoRaWAN Test App uses < strong > Data Rate 3< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L58-L70" > lorawan_test_main.c< / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // LoRaWAN Adaptive Data Rate
// Please note that when ADR is enabled the end-device should be static
#define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_OFF
2022-01-02 12:25:44 +08:00
2022-01-02 13:37:59 +08:00
// Default Data Rate
// Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled
2024-12-04 20:02:50 +08:00
#define LORAWAN_DEFAULT_DATARATE DR_3< / code > < / pre > < / div >
2022-01-02 13:37:59 +08:00
< p > But there’ s a catch: The < strong > First Message Transmitted< / strong > (after joining LoRaWAN) will have < strong > Data Rate 2< / strong > (instead of Data Rate 3)!< / p >
< p > (We’ ll see this in the upcoming demo)< / p >
< p > For Data Rates 2 and 3, the < strong > Maximum Message (Payload) Sizes< / strong > are…< / p >
2022-03-01 17:38:23 +08:00
< div > < table > < thead > < tr > < th style = "text-align: center" > Region< / th > < th style = "text-align: center" > Data Rate< / th > < th style = "text-align: center" > Max Payload Size< / th > < / tr > < / thead > < tbody >
< tr > < td style = "text-align: center" > < strong > AS923< / strong > < / td > < td style = "text-align: center" > DR 2 < br > DR 3< / td > < td style = "text-align: center" > 11 bytes < br > 53 bytes< / td > < / tr >
< tr > < td style = "text-align: center" > < strong > AU915< / strong > < / td > < td style = "text-align: center" > DR 2 < br > DR 3< / td > < td style = "text-align: center" > 11 bytes < br > 53 bytes< / td > < / tr >
< tr > < td style = "text-align: center" > < strong > EU868< / strong > < / td > < td style = "text-align: center" > DR 2 < br > DR 3< / td > < td style = "text-align: center" > 51 bytes < br > 115 bytes< / td > < / tr >
< tr > < td style = "text-align: center" > < strong > US915< / strong > < / td > < td style = "text-align: center" > DR 2 < br > DR 3< / td > < td style = "text-align: center" > 125 bytes < br > 222 bytes< / td > < / tr >
2022-01-02 13:37:59 +08:00
< / tbody > < / table >
< / div >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/" > (Based on LoRaWAN Regional Parameters)< / a > < / p >
< p > Our LoRaWAN Test App sends a Message Payload of < strong > 9 bytes< / strong > , so it should work fine for Data Rates 2 and 3 across all LoRaWAN Regions.< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx5a.png" alt = "Setting LoRaWAN Data Rate to 3" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "message-interval" > < a class = "doc-anchor" href = "#message-interval" > §< / a > 9.2 Message Interval< / h2 >
2022-01-02 13:37:59 +08:00
< p > < em > How often can we send data to the LoRaWAN Network?< / em > < / p >
2022-01-02 14:59:58 +08:00
< p > We must comply with Local Wireless Regulations for < a href = "https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/" > < strong > Duty Cycle< / strong > < / a > . Blasting messages non-stop is no-no!< / p >
< p > To figure out how often we can send data, check out the…< / p >
< ul >
< li > < a href = "https://avbentem.github.io/airtime-calculator/ttn/us915" > < strong > “LoRaWAN Airtime Calculator”< / strong > < / a > < / li >
< / ul >
< p > For < strong > AS923 (Asia) at Data Rate 3< / strong > , the LoRaWAN Airtime Calculator says that we can send a message every < strong > 20.6 seconds< / strong > (assuming Message Payload is < strong > 9 bytes< / strong > )…< / p >
2022-01-02 14:32:21 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-airtime.jpg" alt = "LoRaWAN Airtime Calculator" / > < / p >
2022-01-02 14:59:58 +08:00
< p > < a href = "https://avbentem.github.io/airtime-calculator/ttn/as923/9" > (Source)< / a > < / p >
< p > Let’ s round up the Message Interval to < strong > 40 seconds< / strong > for demo.< / p >
< p > We configure this Message Interval as < strong > APP_TX_DUTYCYCLE< / strong > in < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L47-L56" > lorawan_test_main.c< / a > < / p >
2022-01-02 13:37:59 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Defines the application data transmission duty cycle.
// 40s, value in [ms].
#define APP_TX_DUTYCYCLE 40000
2022-01-02 12:25:44 +08:00
2022-01-02 13:37:59 +08:00
// Defines a random delay for application data transmission duty cycle.
// 5s, value in [ms].
2024-12-04 20:02:50 +08:00
#define APP_TX_DUTYCYCLE_RND 5000< / code > < / pre > < / div >
2022-01-02 14:59:58 +08:00
< p > < strong > APP_TX_DUTYCYCLE< / strong > is used to compute the Timeout Interval of our < strong > Transmit Timer< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L260-L303" > lorawan_test_main.c< / a > < / p >
2022-01-02 13:37:59 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = APP_TX_DUTYCYCLE +
2024-12-04 20:02:50 +08:00
randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/boards/mcu/utilities.c#L48-L51" > (< strong > randr< / strong > is defined here)< / a > < / p >
2024-09-11 15:14:35 +08:00
< p > Thus our LoRaWAN Test App transmits a message every < strong > 40 seconds< / strong > .< / p >
2022-01-02 14:59:58 +08:00
< p > (±5 seconds of random delay)< / p >
2024-03-29 16:55:46 +08:00
< h1 id = "rerun-the-firmware" > < a class = "doc-anchor" href = "#rerun-the-firmware" > §< / a > 10 Rerun The Firmware< / h1 >
2022-01-02 20:52:54 +08:00
< p > Watch what happens when our LoRaWAN Test App < strong > transmits a Data Packet< / strong > …< / p >
2022-01-02 13:37:59 +08:00
< ol >
< li >
< p > In the NuttX Shell, run our < strong > LoRaWAN Test App< / strong > …< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > lorawan_test< / code > < / pre > < / div > < / li >
2022-01-02 13:37:59 +08:00
< li >
2022-01-02 16:00:54 +08:00
< p > As seen earlier, our app transmits a < strong > Join Network Request< / strong > and receives a < strong > Join Accept Response< / strong > from the LoRaWAN Gateway…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ### =========== MLME-Confirm ============ ##
2022-01-02 13:37:59 +08:00
STATUS : OK
2023-01-13 07:19:30 +08:00
### =========== JOINED ============ ##
2022-01-02 13:37:59 +08:00
OTAA
DevAddr : 01DA9790
2024-12-04 20:02:50 +08:00
DATA RATE : DR_2< / code > < / pre > < / div >
2022-01-02 13:37:59 +08:00
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< / li >
< li >
2022-01-02 16:00:54 +08:00
< p > Upon joining the LoRaWAN Network, our app < strong > transmits a Data Packet< / strong > …< / p >
2022-01-02 13:37:59 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
PrepareTxFrame: status=0, maxSize=11, currentSize=11
2023-01-13 07:19:30 +08:00
### =========== MCPS-Request ============ ##
### MCPS_UNCONFIRMED ##
### ===================================== ##
2022-01-02 13:37:59 +08:00
STATUS : OK
2024-12-04 20:02:50 +08:00
PrepareTxFrame: Transmit OK< / code > < / pre > < / div >
2022-01-02 22:08:49 +08:00
< p > Note that the < strong > First Data Packet< / strong > is assumed to have < strong > Data Rate 2< / strong > , which allows Maximum Message Size < strong > 11 bytes< / strong > (for AS923).< / p >
2022-01-02 16:00:54 +08:00
< / li >
< li >
< p > After transmitting the First Data Packet, our LoRaWAN Library automagically upgrades the < strong > Data Rate to 3< / strong > …< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > ### =========== MCPS-Confirm ============ ##
2022-01-02 13:37:59 +08:00
STATUS : OK
2023-01-13 07:19:30 +08:00
### ===== UPLINK FRAME 1 ===== ##
2022-01-02 13:37:59 +08:00
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
2024-12-04 20:02:50 +08:00
CHANNEL MASK: 0003< / code > < / pre > < / div > < / li >
2022-01-02 16:00:54 +08:00
< li >
2022-01-02 16:29:45 +08:00
< p > While transmitting the Second (and subsequent) Data Packet, the Maximum Message Size is extended to < strong > 53 bytes< / strong > (because of the increased Data Rate)…< / p >
2022-01-02 16:00:54 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
2022-01-02 13:37:59 +08:00
PrepareTxFrame: status=0, maxSize=53, currentSize=53
2023-01-13 07:19:30 +08:00
### =========== MCPS-Request ============ ##
### MCPS_UNCONFIRMED ##
### ===================================== ##
2022-01-02 13:37:59 +08:00
STATUS : OK
PrepareTxFrame: Transmit OK
...
2023-01-13 07:19:30 +08:00
### =========== MCPS-Confirm ============ ##
2022-01-02 13:37:59 +08:00
STATUS : OK
2023-01-13 07:19:30 +08:00
### ===== UPLINK FRAME 1 ===== ##
2022-01-02 13:37:59 +08:00
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
2024-12-04 20:02:50 +08:00
CHANNEL MASK: 0003< / code > < / pre > < / div > < / li >
2022-01-02 16:29:45 +08:00
< li >
< p > This repeats roughly every < strong > 40 seconds< / strong > .< / p >
2022-01-02 16:00:54 +08:00
< p > Let’ s check the logs in our LoRaWAN Gateway.< / p >
2022-01-02 13:37:59 +08:00
< / li >
< / ol >
2022-01-03 13:22:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx7a.jpg" alt = "Data Rate changes from 2 to 3" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "check-lorawan-gateway-1" > < a class = "doc-anchor" href = "#check-lorawan-gateway-1" > §< / a > 10.1 Check LoRaWAN Gateway< / h2 >
2022-01-02 22:29:09 +08:00
< p > To inspect the Data Packet on our < strong > LoRaWAN Gateway< / strong > (ChirpStack), click…< / p >
2022-01-02 16:07:42 +08:00
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > LoRaWAN Frames< / strong > < / p >
2022-01-02 22:29:09 +08:00
< p > And look for < strong > “Unconfirmed Data Up”< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack8.png" alt = "Send Data" / > < / p >
2022-01-02 16:29:45 +08:00
< p > To see the < strong > Decoded Payload< / strong > of our Data Packet, click…< / p >
2022-01-02 16:07:42 +08:00
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > Device Data< / strong > < / p >
2022-01-02 16:41:14 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack6.png" alt = "Decoded Payload" / > < / p >
2022-01-02 22:29:09 +08:00
< p > If we see < strong > “Hi NuttX”< / strong > … Congratulations our LoRaWAN Test App has successfully transmitted a Data Packet to LoRaWAN!< / p >
2022-01-01 19:13:46 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow2.jpg" alt = "Join LoRaWAN Network" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "lorawan-nonce" > < a class = "doc-anchor" href = "#lorawan-nonce" > §< / a > 11 LoRaWAN Nonce< / h1 >
2022-01-02 16:54:11 +08:00
< p > < em > Why did we configure NuttX to provide a Strong Random Number Generator with Entropy Pool?< / em > < / p >
2022-01-02 18:09:43 +08:00
< p > The Strong Random Number Generator fixes a < strong > Nonce Quirk< / strong > in our LoRaWAN Library that we observed during development…< / p >
< ul >
< li >
< p > Remember that our LoRaWAN Library < strong > sends a Nonce< / strong > to the LoRaWAN Gateway every time it starts. (Pic above)< / p >
< / li >
< li >
< p > What’ s a Nonce? It’ s a < strong > Non-Repeating Number< / strong > that prevents < a href = "https://en.wikipedia.org/wiki/Replay_attack" > < strong > Replay Attacks< / strong > < / a > < / p >
< / li >
< li >
< p > By default our LoRaWAN Library < strong > initialises the Nonce to 1< / strong > and increments by 1 for every Join Network Request: 1, 2, 3, 4, …< / p >
< / li >
< / ul >
< p > Now suppose the LoRaWAN Library < strong > crashes our device< / strong > due to a bug. Watch what happens…< / p >
2022-03-01 17:38:23 +08:00
< div > < table > < thead > < tr > < th style = "text-align: left" > < em > Our Device< / em > < / th > < th style = "text-align: left" > < em > LoRaWAN Gateway< / em > < / th > < / tr > < / thead > < tbody >
< tr > < td style = "text-align: left" > Here is < strong > Nonce 1< / strong > < / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < / td > < td style = "text-align: left" > OK I accept < strong > Nonce 1< / strong > < / td > < / tr >
< tr > < td style = "text-align: left" > (Device crashes and restarts)< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > Here is < strong > Nonce 1< / strong > < / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < / td > < td style = "text-align: left" > (Silently rejects < strong > Nonce 1< / strong > because it’ s repeated)< / td > < / tr >
< tr > < td style = "text-align: left" > (Timeout waiting for response)< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > Here is < strong > Nonce 2< / strong > < / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < / td > < td style = "text-align: left" > OK I accept < strong > Nonce 2< / strong > < / td > < / tr >
< tr > < td style = "text-align: left" > (Device crashes and restarts)< / td > < td style = "text-align: left" > < / td > < / tr >
2022-01-02 18:09:43 +08:00
< / tbody > < / table >
< / div >
< p > If our device keeps crashing, the LoRaWAN Gateway will eventually < strong > reject a whole bunch of Nonces< / strong > : 1, 2, 3, 4, …< / p >
< p > (Which makes development super slow and frustrating)< / p >
< p > Thus we generate LoRaWAN Nonces with a < strong > Strong Random Number Generator< / strong > instead.< / p >
< p > (Random Numbers that won’ t repeat upon restarting)< / p >
2022-01-03 13:22:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack2a.jpg" alt = "Repeated Nonces are rejected by LoRaWAN Gateway" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "strong-random-number-generator" > < a class = "doc-anchor" href = "#strong-random-number-generator" > §< / a > 11.1 Strong Random Number Generator< / h2 >
2022-01-02 18:17:58 +08:00
< p > Our LoRaWAN Library supports < strong > Random Nonces< / strong > … Assuming that we have a < strong > Secure Element< / strong > .< / p >
< p > Since we don’ t have a Secure Element, let’ s < strong > generate the Random Nonce in software< / strong > : < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/nuttx.c#L140-L152" > nuttx.c< / a > < / p >
2022-01-02 17:13:31 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > /// Get random devnonce from the Random Number Generator
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum ) {
2022-01-02 18:09:43 +08:00
// Open the Random Number Generator /dev/urandom
int fd = open(" /dev/urandom" , O_RDONLY);
assert(fd > 0);
2022-01-02 17:13:31 +08:00
2022-01-02 18:09:43 +08:00
// Read the random number
read(fd, randomNum, sizeof(uint32_t));
close(fd);
2022-01-02 17:13:31 +08:00
2022-01-02 18:09:43 +08:00
printf(" SecureElementRandomNumber: 0x%08lx\n" , *randomNum);
return SECURE_ELEMENT_SUCCESS;
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-02 18:32:07 +08:00
< p > The above code is called by our LoRaWAN Library when preparing a < strong > Join Network Request< / strong > : < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/mac/LoRaMacCrypto.c#L980-L996" > LoRaMacCrypto.c< / a > < / p >
2022-01-02 18:45:21 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Prepare a Join Network Request
LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest_t* macMsg ) {
2022-01-02 17:13:31 +08:00
#if ( USE_RANDOM_DEV_NONCE == 1 )
2022-01-02 18:09:43 +08:00
// Get Nonce from Random Number Generator
uint32_t devNonce = 0;
SecureElementRandomNumber( & devNonce );
CryptoNvm-> DevNonce = devNonce;
2022-01-02 17:13:31 +08:00
#else
2022-01-02 18:09:43 +08:00
// Init Nonce to 1
CryptoNvm-> DevNonce++;
2024-12-04 20:02:50 +08:00
#endif< / code > < / pre > < / div >
2022-01-02 18:32:07 +08:00
< p > To enable Random Nonces, we define < strong > USE_RANDOM_DEV_NONCE< / strong > as 1 in < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/mac/LoRaMacCrypto.h#L58-L65" > LoRaMacCrypto.h< / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // Indicates if a random devnonce must be used or not
#ifdef __NuttX__
// For NuttX: Get random devnonce from the Random Number Generator
2022-01-02 18:09:43 +08:00
#define USE_RANDOM_DEV_NONCE 1
2022-01-02 17:13:31 +08:00
#else
2022-01-02 18:09:43 +08:00
#define USE_RANDOM_DEV_NONCE 0
2024-12-04 20:02:50 +08:00
#endif // __NuttX__< / code > < / pre > < / div >
2022-01-02 21:09:32 +08:00
< p > And that’ s how we generate Random Nonces whenever we restart our device! (Pic below)< / p >
2022-01-02 18:51:05 +08:00
< p > < em > What happens if we don’ t select Entropy Pool for our Random Number Generator?< / em > < / p >
< p > Our Random Number Generator becomes “Weak”… It < strong > repeats the same Random Numbers< / strong > upon restarting.< / p >
2022-01-02 21:09:32 +08:00
< p > Thus we < strong > always select Entropy Pool< / strong > for our Random Number Generator…< / p >
2022-01-02 18:51:05 +08:00
< ul >
< li > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-random-number-generator-with-entropy-pool" > < strong > “Random Number Generator with Entropy Pool”< / strong > < / a > < / li >
< / ul >
2022-01-23 12:28:36 +08:00
< p > < strong > UPDATE:< / strong > While running Auto Flash and Test with NuttX, we discovered that the Random Number Generator with Entropy Pool might < strong > generate the same Random Numbers< / strong > . (Because the booting of NuttX becomes so predictable)< / p >
< p > To fix this, we add < strong > Internal Temperature Sensor Data< / strong > to the Entropy Pool, to generate truly random numbers…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/auto#appendix-fix-lorawan-nonce" > < strong > “Fix LoRaWAN Nonce”< / strong > < / a > < / li >
< / ul >
2022-01-03 13:22:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce7a.jpg" alt = "Our LoRaWAN Library now generates random nonces" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "lorawan-event-loop" > < a class = "doc-anchor" href = "#lorawan-event-loop" > §< / a > 12 LoRaWAN Event Loop< / h1 >
2022-01-02 22:02:27 +08:00
< p > Let’ s look inside our LoRaWAN Test App and learn how the < strong > Event Loop< / strong > handles LoRa and LoRaWAN Events by calling NimBLE Porting Layer.< / p >
< p > < em > What is NimBLE Porting Layer?< / em > < / p >
< p > < strong > NimBLE Porting Layer< / strong > is a multithreading library that works on several operating systems…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/sx1262#multithreading-with-nimble-porting-layer" > < strong > “Multithreading with NimBLE Porting Layer”< / strong > < / a > < / li >
< / ul >
< p > It provides < strong > Timers and Event Queues< / strong > that are used by the LoRa and LoRaWAN Libraries.< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run5a.png" alt = "Timers and Event Queues" / > < / p >
< p > < em > What’ s inside our Event Loop?< / em > < / p >
< p > Our < strong > Event Loop< / strong > forever reads LoRa and LoRaWAN Events from an < strong > Event Queue< / strong > and handles them.< / p >
2022-01-02 22:38:00 +08:00
< p > The Event Queue is created in our LoRa SX1262 Library as explained here…< / p >
2022-01-02 22:02:27 +08:00
< ul >
< li > < a href = "https://lupyuen.github.io/articles/sx1262#event-queue" > < strong > “Event Queue”< / strong > < / a > < / li >
< / ul >
< p > The Main Function of our LoRaWAN Test App calls this function to run the < strong > Event Loop< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L611-L655" > lorawan_test_main.c< / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > /// Event Loop that dequeues Events from the Event Queue and processes the Events
static void handle_event_queue(void *arg) {
// Loop forever handling Events from the Event Queue
for (;;) {
// Get the next Event from the Event Queue
struct ble_npl_event *ev = ble_npl_eventq_get(
& event_queue, // Event Queue
BLE_NPL_TIME_FOREVER // No Timeout (Wait forever for event)
2024-12-04 20:02:50 +08:00
);< / code > < / pre > < / div >
2022-01-02 22:02:27 +08:00
< p > This code runs in the < strong > Foreground Thread< / strong > of our NuttX App.< / p >
< p > Here we loop forever, < strong > waiting for Events< / strong > from the Event Queue.< / p >
< p > When we receive an Event, we < strong > remove the Event< / strong > from the Event Queue…< / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // If no Event due to timeout, wait for next Event.
// Should never happen since we wait forever for an Event.
if (ev == NULL) { printf(" ." ); continue; }
// Remove the Event from the Event Queue
2024-12-04 20:02:50 +08:00
ble_npl_eventq_remove(& event_queue, ev);< / code > < / pre > < / div >
2022-01-02 22:02:27 +08:00
< p > We call the < strong > Event Handler Function< / strong > that was registered with the Event…< / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // Trigger the Event Handler Function
2024-12-04 20:02:50 +08:00
ble_npl_event_run(ev);< / code > < / pre > < / div >
2021-12-30 16:35:12 +08:00
< ul >
2022-01-02 22:02:27 +08:00
< li >
< p > For SX1262 Interrupts: We call < a href = "https://lupyuen.github.io/articles/sx1262#radioondioirq" > < strong > RadioOnDioIrq< / strong > < / a > to handle the packet transmitted / received notification< / p >
< / li >
< li >
< p > For Timer Events: We call the < strong > Timeout Function< / strong > defined in the Timer< / p >
< / li >
2021-12-30 16:35:12 +08:00
< / ul >
2022-01-02 22:02:27 +08:00
< p > The rest of the Event Loop handles < strong > LoRaWAN Events< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // For LoRaWAN: Process the LoRaMAC events
2024-12-04 20:02:50 +08:00
LmHandlerProcess( );< / code > < / pre > < / div >
2022-01-02 22:38:00 +08:00
< p > < strong > LmHandlerProcess< / strong > handles < strong > Join Network Events< / strong > in the LoRaMAC Layer of our LoRaWAN Library.< / p >
2022-01-02 22:19:54 +08:00
< p > If we have joined the LoRaWAN Network, we < strong > transmit data< / strong > to the network…< / p >
2022-01-02 22:02:27 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // For LoRaWAN: If we have joined the network, do the uplink
if (!LmHandlerIsBusy( )) {
UplinkProcess( );
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-02 22:19:54 +08:00
< p > (< a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L361-L373" > < strong > UplinkProcess< / strong > < / a > calls < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L305-L337" > < strong > PrepareTxFrame< / strong > < / a > , which we have seen earlier)< / p >
< p > The last part of the Event Loop will handle Low Power Mode in future…< / p >
2022-01-02 22:02:27 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // For LoRaWAN: Handle Low Power Mode
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
// TODO: BoardLowPowerHandler( );
}
CRITICAL_SECTION_END( );
}
2024-12-04 20:02:50 +08:00
}< / code > < / pre > < / div >
2022-01-03 09:31:52 +08:00
< p > And we loop back perpetually, waiting for Events and handling them.< / p >
2022-01-02 22:02:27 +08:00
< p > That’ s how we handle LoRa and LoRaWAN Events with NimBLE Porting Layer!< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-npl1.png" alt = "Handling LoRaWAN Events with NimBLE Porting Layer" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "troubleshoot-lorawan" > < a class = "doc-anchor" href = "#troubleshoot-lorawan" > §< / a > 13 Troubleshoot LoRaWAN< / h1 >
2022-01-03 09:31:52 +08:00
< p > < em > The Join Network Request / Join Accept Response / Data Packet doesn’ t appear in the LoRaWAN Gateway…< / em > < / p >
< p > < em > What can we check?< / em > < / p >
< ol >
< li >
< p > In the output of our LoRaWAN Test App, verify the < strong > Sync Word< / strong > (must be 3444), < strong > Device EUI< / strong > (MSB First), < strong > Join EUI< / strong > (MSB First) and < strong > LoRa Frequency< / strong > …< / p >
2022-01-03 10:10:32 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > RadioSetPublicNetwork: public syncword=3444
DevEui : 4B-C1-5E-E7-37-7B-B1-5B
JoinEui : 00-00-00-00-00-00-00-00
2024-12-04 20:02:50 +08:00
RadioSetChannel: freq=923400000< / code > < / pre > < / div >
2022-01-03 09:31:52 +08:00
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run2a.png" alt = "LoRa Frequency, Sync Word, Device EUI and Join EUI" / > < / p >
< / li >
< li >
< p > Verify the < strong > App Key< / strong > (MSB First) in < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/peripherals/soft-se/se-identity.h#L65-L79" > < strong > se-identity.h< / strong > < / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#device-eui-join-eui-and-app-key" > < strong > “Device EUI, Join EUI and App Key”< / strong > < / a > < / p >
< / li >
< li >
2022-02-02 12:25:47 +08:00
< p > On our LoRaWAN Gateway, scan the log for < strong > Message Integrity Code< / strong > errors (“invalid MIC”)…< / p >
2022-01-03 09:31:52 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > grep MIC /var/log/syslog
chirpstack-application-server[568]:
level=error
msg=" invalid MIC"
dev_eui=4bc15ee7377bb15b
2024-12-04 20:02:50 +08:00
type=DATA_UP_MIC< / code > < / pre > < / div >
2022-01-03 09:31:52 +08:00
< p > This is usually caused by incorrect Device EUI, Join EUI or App Key.< / p >
2022-01-03 10:10:32 +08:00
< p > < a href = "https://lupyuen.github.io/articles/wisgate#message-integrity-code" > (More about Message Integrity Code)< / a > < / p >
2022-01-03 09:31:52 +08:00
< / li >
< li >
2022-02-02 12:25:47 +08:00
< p > On our LoRaWAN Gateway, scan the log for < strong > Nonce Errors< / strong > (“validate dev-nonce error”)…< / p >
2022-01-03 09:31:52 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > grep nonce /var/log/syslog
chirpstack-application-server[5667]:
level=error
msg=" validate dev-nonce error"
dev_eui=4bc15ee7377bb15b
type=OTAA
chirpstack-network-server[5749]:
time=" 2021-12-26T06:12:48Z"
level=error
msg=" uplink: processing uplink frame error"
ctx_id=bb756ec1-9ee3-4903-a13d-656356d98fd5
2024-12-04 20:02:50 +08:00
error=" validate dev-nonce error: object already exists" < / code > < / pre > < / div >
2022-01-03 09:31:52 +08:00
< p > This means that a < strong > Duplicate Nonce< / strong > has been detected.< / p >
< p > Check that we’ re using a Strong Random Number Generator with Entropy Pool…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-random-number-generator-with-entropy-pool" > < strong > “Random Number Generator with Entropy Pool”< / strong > < / a > < / p >
< / li >
< li >
2022-01-23 12:21:59 +08:00
< p > Another way to check for < strong > Duplicate Nonce< / strong > : Click…< / p >
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > Device Data< / strong > < / p >
< p > Look for < strong > “validate dev-nonce error”< / strong > …< / p >
< p > < img src = "https://lupyuen.github.io/images/auto-nonce.png" alt = "Duplicate LoRaWAN Nonce" / > < / p >
< / li >
< li >
2022-01-03 09:31:52 +08:00
< p > Disable all < strong > Info Logging< / strong > on NuttX< / p >
2022-01-03 09:57:57 +08:00
< p > (See < strong > “LoRaWAN is Time Sensitive”< / strong > below)< / p >
2022-01-03 09:31:52 +08:00
< / li >
< li >
< p > Verify the < strong > Message Size< / strong > for the Data Rate< / p >
2022-01-03 11:08:08 +08:00
< p > (See < strong > “Empty LoRaWAN Message”< / strong > below)< / p >
2022-01-03 09:31:52 +08:00
< / li >
< li >
2022-08-03 09:51:27 +08:00
< p > If we < strong > fail to join< / strong > the LoRaWAN Network, see these tips…< / p >
< p > < a href = "https://gist.github.com/lupyuen/c03870b103f51649dcf608ffb1bc9e6b" > < strong > “Troubleshoot LoRaWAN on NuttX”< / strong > < / a > < / p >
< / li >
< li >
2022-01-03 09:31:52 +08:00
< p > More troubleshooting tips…< / p >
< p > < a href = "https://lupyuen.github.io/articles/wisgate#troubleshoot-lorawan" > < strong > “Troubleshoot LoRaWAN”< / strong > < / a > < / p >
< / li >
< / ol >
2024-03-29 16:55:46 +08:00
< h2 id = "lorawan-is-time-sensitive" > < a class = "doc-anchor" href = "#lorawan-is-time-sensitive" > §< / a > 13.1 LoRaWAN is Time Sensitive< / h2 >
2022-01-03 10:10:32 +08:00
< p > < strong > Warning:< / strong > LoRaWAN is Time Sensitive!< / p >
< p > Our LoRaWAN Library needs to < strong > handle Events in a timely manner< / strong > … Or the protocol fails.< / p >
2022-01-03 09:57:57 +08:00
< p > This is the normal flow for the < strong > Join Network Request< / strong > …< / p >
2022-03-01 17:38:23 +08:00
< div > < table > < thead > < tr > < th style = "text-align: left" > < em > Our Device< / em > < / th > < th style = "text-align: left" > < em > LoRaWAN Gateway< / em > < / th > < / tr > < / thead > < tbody >
< tr > < td style = "text-align: left" > Join Network Request →< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > Transmit OK Interrupt< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > Switch to Receive Mode< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < / td > < td style = "text-align: left" > ← Join Accept Response< / td > < / tr >
< tr > < td style = "text-align: left" > Handle Join Response< / td > < td style = "text-align: left" > < / td > < / tr >
2022-01-03 09:57:57 +08:00
< / tbody > < / table >
< / div >
< p > Watch what happens if < strong > our device gets too busy< / strong > …< / p >
2022-03-01 17:38:23 +08:00
< div > < table > < thead > < tr > < th style = "text-align: left" > < em > Our Device< / em > < / th > < th style = "text-align: left" > < em > LoRaWAN Gateway< / em > < / th > < / tr > < / thead > < tbody >
< tr > < td style = "text-align: left" > Join Network Request →< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > Transmit OK Interrupt< / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < strong > (Busy Busy)< / strong > < / td > < td style = "text-align: left" > ← Join Accept Response< / td > < / tr >
< tr > < td style = "text-align: left" > < strong > Switch to Receive Mode< / strong > < / td > < td style = "text-align: left" > < / td > < / tr >
< tr > < td style = "text-align: left" > < strong > Join Response missing!< / strong > < / td > < td style = "text-align: left" > < / td > < / tr >
2022-01-03 09:57:57 +08:00
< / tbody > < / table >
< / div >
2022-01-03 11:08:08 +08:00
< p > This might happen if our device is busy < strong > writing debug logs< / strong > to the console.< / p >
2022-05-30 10:21:51 +08:00
< p > < a href = "https://gist.github.com/lupyuen/1d96b24c6bf5164cba652d903eedb9d1" > (LoRaWAN Gateway returns the Join Accept Response in a One-Second Window)< / a > < / p >
2022-01-03 11:08:08 +08:00
< p > Thus we should < strong > disable Info Logging< / strong > on NuttX…< / p >
< ol >
< li >
2024-09-11 15:14:35 +08:00
< p > In < strong > menuconfig< / strong > , select < strong > “Build Setup”< / strong > → < strong > “Debug Options”< / strong > < / p >
2022-01-03 11:08:08 +08:00
< / li >
< li >
< p > < strong > Uncheck< / strong > the following…< / p >
< ul >
< li > < strong > Enable Info Debug Output< / strong > < / li >
< li > < strong > GPIO Info Output< / strong > < / li >
< li > < strong > SPI Info Output< / strong > < / li >
< / ul >
< / li >
< / ol >
< p > (It’ s OK to enable Debug Assertions, Error Output and Warning Output)< / p >
2022-05-30 09:40:23 +08:00
< p > Since LoRaWAN is Time Sensitive, we ought to < a href = "https://lupyuen.github.io/articles/lorawan3#spi-with-dma" > < strong > optimise SPI Data Transfers with DMA< / strong > < / a > .< / p >
< ul >
< li > < a href = "https://gist.github.com/lupyuen/1d96b24c6bf5164cba652d903eedb9d1" > < strong > Why LoRaWAN is Time Critical< / strong > < / a > < / li >
< / ul >
2022-01-03 09:57:57 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx.png" alt = "LoRaWAN is Time Sensitive" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/8f012856b9eb6b9a762160afd83df7f8" > (Source)< / a > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "empty-lorawan-message" > < a class = "doc-anchor" href = "#empty-lorawan-message" > §< / a > 13.2 Empty LoRaWAN Message< / h2 >
2022-01-03 11:08:08 +08:00
< p > < em > What happens when we send a message that’ s too large?< / em > < / p >
< p > Our LoRaWAN Library will transmit an < strong > Empty Message Payload!< / strong > < / p >
< p > We’ ll see this in the LoRaWAN Gateway…< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack5.png" alt = "Empty Message Payload" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/0d301216bbf937147778bb57ab0ccf89" > (Output Log)< / a > < / p >
2024-09-11 15:14:35 +08:00
< p > In the output for our LoRaWAN Test App, look for < strong > “maxSize”< / strong > to verify the < strong > Maximum Message Size< / strong > for our Data Rate and LoRaWAN Region…< / p >
2022-01-03 11:08:08 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
2024-12-04 20:02:50 +08:00
PrepareTxFrame: status=0, maxSize=11, currentSize=11< / code > < / pre > < / div >
2022-01-03 11:08:08 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#message-size" > (More about Message Size)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx4a.png" alt = "Checking message size" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/5fc07695a6c4bb48b5e4d10eb05ca9bf" > (Source)< / a > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "spi-with-dma" > < a class = "doc-anchor" href = "#spi-with-dma" > §< / a > 14 SPI With DMA< / h1 >
2022-04-19 12:33:39 +08:00
< p > Today we have successfully tested the LoRaWAN Library on < a href = "https://lupyuen.github.io/articles/pinedio2" > < strong > PineDio Stack BL604 RISC-V Board< / strong > < / a > (pic below) and its onboard Semtech SX1262 Transceiver.< / p >
2022-01-03 11:55:52 +08:00
< p > The NuttX implementation of < strong > SPI on BL602 and BL604< / strong > might need some enhancements…< / p >
< ul >
< li >
< p > NuttX on BL602 / BL604 executes < strong > SPI Data Transfer with Polling< / strong > (not DMA)< / p >
2022-11-30 12:01:12 +08:00
< p > < a href = "https://github.com/lupyuen/nuttx/blob/lorawan/arch/risc-v/src/bl602/bl602_spi.c#L734-L803" > (See this)< / a > < / p >
2022-01-03 11:55:52 +08:00
< / li >
< li >
< p > LoRaWAN is < strong > Time Sensitive< / strong > , as explained earlier. SPI with Polling might cause < strong > incoming packets to be dropped< / strong > .< / p >
< p > (SPI with DMA is probably better for LoRaWAN)< / p >
< / li >
< li >
2022-04-19 12:33:39 +08:00
< p > We’ re testing NuttX and LoRaWAN on < a href = "https://lupyuen.github.io/articles/pinedio2" > < strong > PineDio Stack BL604< / strong > < / a > , which comes with an onboard < strong > ST7789 SPI Display< / strong > .< / p >
2022-01-03 11:55:52 +08:00
< p > < strong > ST7789 works better with DMA< / strong > when blasting pixels to the display.< / p >
< / li >
< li >
< p > We might have < strong > contention between ST7789 and SX1262< / strong > if we do SPI with Polling< / p >
< p > (How would we multitask LoRaWAN with Display Updates?)< / p >
< / li >
< / ul >
< p > Hence we might need to < strong > implement SPI with DMA< / strong > real soon on BL602 and BL604.< / p >
< p > We could port the implementation of SPI DMA from < strong > BL602 IoT SDK< / strong > to NuttX…< / p >
2022-01-03 11:26:53 +08:00
< ul >
2022-01-03 11:55:52 +08:00
< li >
< p > < a href = "https://lupyuen.github.io/articles/spi#lli_list_init-create-dma-linked-list" > < strong > “Create DMA Linked List”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/articles/spi#hal_spi_dma_trans-execute-spi-transfer-with-dma" > < strong > “Execute SPI Transfer with DMA”< / strong > < / a > < / p >
< / li >
2022-01-03 11:26:53 +08:00
< / ul >
2022-11-18 17:17:44 +08:00
< p > < strong > UPDATE:< / strong > SPI DMA is now supported on BL602 NuttX…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/spi2#appendix-spi-dma-on-bl602-nuttx" > < strong > “SPI DMA on BL602 NuttX”< / strong > < / a > < / li >
< / ul >
2022-01-02 22:02:27 +08:00
< p > < img src = "https://lupyuen.github.io/images/spi2-pinedio1.jpg" alt = "Inside PineDio Stack BL604" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "whats-next" > < a class = "doc-anchor" href = "#whats-next" > §< / a > 15 What’ s Next< / h1 >
2022-01-03 13:02:05 +08:00
< p > We’ re ready to build a < strong > complete IoT Sensor Device< / strong > with NuttX!< / p >
2022-01-03 12:23:47 +08:00
< p > Now that LoRaWAN is up, we’ ll carry on in the next few articles…< / p >
< ul >
< li >
2022-01-05 17:46:44 +08:00
< p > Implement < a href = "https://github.com/intel/tinycbor" > < strong > CBOR on NuttX< / strong > < / a > for compressing Sensor Data…< / p >
< p > < a href = "https://lupyuen.github.io/articles/cbor2" > < strong > “Encode Sensor Data with CBOR on Apache NuttX OS”< / strong > < / a > < / p >
2022-01-03 12:23:47 +08:00
< / li >
< li >
2022-01-14 06:57:22 +08:00
< p > Transmit the compressed Sensor Data to < a href = "https://lupyuen.github.io/articles/ttn" > < strong > The Things Network< / strong > < / a > over LoRaWAN< / p >
< p > (Pic below)< / p >
2022-01-03 12:23:47 +08:00
< / li >
< li >
2022-01-14 06:57:22 +08:00
< p > We’ ll read BL602’ s < a href = "https://lupyuen.github.io/articles/tsen" > < strong > Internal Temperature Sensor< / strong > < / a > to get real Sensor Data…< / p >
< p > < a href = "https://github.com/lupyuen/bl602_adc_test" > < strong > “ADC and Internal Temperature Sensor Library”< / strong > < / a > < / p >
2022-01-03 12:23:47 +08:00
< / li >
< / ul >
2021-12-30 10:58:30 +08:00
< p > < em > We’ re porting plenty of code to NuttX: LoRa, LoRaWAN and NimBLE Porting Layer. Do we expect any problems?< / em > < / p >
2022-01-02 22:02:27 +08:00
< p > Yep we might have issues keeping our LoRaWAN Stack in sync with Semtech’ s version. < a href = "https://lupyuen.github.io/articles/lorawan3#notes" > (But we shall minimise the changes)< / a > < / p >
2022-03-22 10:19:07 +08:00
< p > We have ported the < a href = "https://lupyuen.github.io/articles/nuttx#rust-on-nuttx" > < strong > Rust Embedded HAL< / strong > < / a > to NuttX. Here’ s what we’ ve done…< / p >
2022-01-06 18:45:37 +08:00
< ul >
2022-03-22 10:19:07 +08:00
< li >
< p > < a href = "https://lupyuen.github.io/articles/rust2" > < strong > “Rust on Apache NuttX OS”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/articles/rusti2c" > < strong > “Rust talks I2C on Apache NuttX RTOS”< / strong > < / a > < / p >
< / li >
2022-01-06 18:45:37 +08:00
< / ul >
2024-12-28 10:07:21 +08:00
< p > Many Thanks to my < a href = "https://lupyuen.github.io/articles/sponsor" > < strong > GitHub Sponsors< / strong > < / a > for supporting my work! This article wouldn’ t have been possible without your support.< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li >
2024-12-28 10:07:21 +08:00
< p > < a href = "https://lupyuen.github.io/articles/sponsor" > Sponsor me a coffee< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
2022-01-03 13:34:54 +08:00
< p > < a href = "https://www.reddit.com/r/Lora/comments/ruu3jf/lorawan_on_apache_nuttx_os/" > Discuss this article on Reddit< / a > < / p >
< / li >
< li >
2021-12-30 10:58:30 +08:00
< p > < a href = "https://lupyuen.github.io/articles/book" > Read “The RISC-V BL602 / BL604 Book”< / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io" > Check out my articles< / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/rss.xml" > RSS Feed< / a > < / p >
< / li >
< / ul >
< p > < em > Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…< / em > < / p >
< p > < a href = "https://github.com/lupyuen/lupyuen.github.io/blob/master/src/lorawan3.md" > < code > lupyuen.github.io/src/lorawan3.md< / code > < / a > < / p >
2022-01-04 16:30:51 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-ttn.png" alt = "NuttX transmits a CBOR Payload to The Things Network Over LoRaWAN" / > < / p >
< p > < em > NuttX transmits a CBOR Payload to The Things Network Over LoRaWAN< / em > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "notes" > < a class = "doc-anchor" href = "#notes" > §< / a > 16 Notes< / h1 >
2021-12-30 10:58:30 +08:00
< ol >
< li >
< p > This article is the expanded version of < a href = "https://twitter.com/MisterTechBlog/status/1473593455699841027" > this Twitter Thread< / a > < / p >
< / li >
< li >
< p > We’ re < strong > porting plenty of code< / strong > to NuttX: LoRa, LoRaWAN and NimBLE Porting Layer. Do we expect any problems?< / p >
< ul >
< li >
< p > If we implement LoRa and LoRaWAN as < strong > NuttX Drivers< / strong > , we’ ll have to scrub the code to comply with the < a href = "https://nuttx.apache.org/docs/latest/contributing/coding_style.html" > < strong > NuttX Coding Conventions< / strong > < / a > .< / p >
< p > This makes it < strong > harder to update< / strong > the LoRaWAN Driver when there are changes in the LoRaWAN Spec. (Like for a new LoRaWAN Region)< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan#appendix-lora-carrier-sensing" > (Here’ s an example)< / a > < / p >
< / li >
< li >
2022-11-30 12:01:12 +08:00
< p > Alternatively we may implement LoRa and LoRaWAN as < strong > External Libraries< / strong > , similar to < a href = "https://github.com/lupyuen/nuttx-apps/tree/master/wireless/bluetooth/nimble" > < strong > NimBLE for NuttX< / strong > < / a > .< / p >
< p > (The < a href = "https://github.com/lupyuen/nuttx-apps/blob/master/wireless/bluetooth/nimble/Makefile#L33" > < strong > Makefile< / strong > < / a > downloads the External Library during build)< / p >
2021-12-30 10:58:30 +08:00
< p > But then we won’ t get a proper NuttX Driver that exposes the ioctl() interface to NuttX Apps.< / p >
< / li >
< / ul >
< p > Conundrum. Lemme know your thoughts!< / p >
< / li >
< li >
< p > How do other Embedded Operating Systems implement LoRaWAN?< / p >
< ul >
< li >
< p > < strong > Mynewt< / strong > embeds a < a href = "https://github.com/apache/mynewt-core/tree/master/net/lora/node" > < strong > Partial Copy< / strong > < / a > of Semtech’ s LoRaWAN Stack into its source tree.< / p >
< / li >
< li >
< p > < strong > Zephyr< / strong > maintains a < a href = "https://github.com/zephyrproject-rtos/loramac-node" > < strong > Complete Fork< / strong > < / a > of the entire LoRaWAN Repo by Semtech. Which gets embedded during the Zephyr build.< / p >
< / li >
< / ul >
2022-01-03 12:35:07 +08:00
< p > We’ re adopting the Zephyr approach to < strong > keep our LoRaWAN Stack in sync< / strong > with Semtech’ s.< / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
< p > We have already ported LoRaWAN to < strong > BL602 IoT SDK< / strong > < a href = "https://lupyuen.github.io/articles/lorawan" > (see this)< / a > , why are we porting again to NuttX?< / p >
< p > Regrettably BL602 IoT SDK has been revamped (without warning) to the < strong > new “hosal” HAL< / strong > < a href = "https://twitter.com/MisterTechBlog/status/1456259223323508748" > (see this)< / a > , and the LoRaWAN Stack will < strong > no longer work< / strong > on the revamped BL602 IoT SDK.< / p >
< p > For easier maintenance, we shall < strong > code our BL602 and BL604 projects with Apache NuttX OS< / strong > instead.< / p >
< p > (Which won’ t get revamped overnight!)< / p >
< / li >
< li >
2022-01-03 15:10:33 +08:00
< p > Will < strong > NuttX become the official OS< / strong > for PineDio Stack BL604 when it goes on sale?< / p >
2022-01-03 12:06:31 +08:00
< p > It might! But first let’ s get LoRaWAN and ST7789 Display running together on PineDio Stack.< / p >
< / li >
< li >
2022-01-03 15:10:33 +08:00
< p > LoRaWAN on NuttX is a great way to < strong > test a new gadget< / strong > like PineDio Stack BL604!< / p >
< p > Today we have tested: SPI Bus, GPIO Input / Output / Interrupt, Multithreading, Timers and Message Queues!< / p >
< / li >
< li >
2022-01-03 13:02:05 +08:00
< p > Is there another solution for the < strong > Nonce Quirk?< / strong > < / p >
< p > We could store the Last Used Nonce into < strong > Non-Volatile Memory< / strong > to be sure that we don’ t reuse the Nonce.< / p >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/nuttx.c#L68-L97" > (See this)< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< / ol >
2024-03-29 16:55:46 +08:00
< h1 id = "appendix-posix-timers-and-message-queues" > < a class = "doc-anchor" href = "#appendix-posix-timers-and-message-queues" > §< / a > 17 Appendix: POSIX Timers and Message Queues< / h1 >
2022-01-01 09:47:11 +08:00
< p > NimBLE Porting Layer needs < strong > POSIX Timers and Message Queues< / strong > (plus more) to work. Follow the steps below to enable the features in < strong > menuconfig< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Disable NuttX Interfaces”< / strong > < / p >
< p > Uncheck < strong > “Disable POSIX Timers”< / strong > < / p >
< p > Uncheck < strong > “Disable POSIX Message Queue Support”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Clocks and Timers”< / strong > < / p >
< p > Check < strong > “Support CLOCK_MONOTONIC”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Work Queue Support”< / strong > < / p >
< p > Check < strong > “High Priority (Kernel) Worker Thread”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Signal Configuration”< / strong > < / p >
< p > Check < strong > “Support SIGEV_THHREAD”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
2022-01-03 13:22:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-config1.jpg" alt = "Enable POSIX Timers and Message Queues in menuconfig" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "appendix-random-number-generator-with-entropy-pool" > < a class = "doc-anchor" href = "#appendix-random-number-generator-with-entropy-pool" > §< / a > 18 Appendix: Random Number Generator with Entropy Pool< / h1 >
2024-09-11 15:14:35 +08:00
< p > Our LoRaWAN Library generates Nonces by calling a < strong > Random Number Generator with Entropy Pool< / strong > .< / p >
2022-01-01 09:47:11 +08:00
< p > Follow these steps to enable the < strong > Entropy Pool< / strong > in < strong > menuconfig< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “Crypto API”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Crypto API Support”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Entropy Pool and Strong Random Number Generator”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce3a.png" alt = "Enable Entropy Pool in menuconfig" / > < / p >
< p > Then we enable the < strong > Random Number Generator< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “Device Drivers”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Enable /dev/urandom”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “/dev/urandom algorithm”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Entropy Pool”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
2022-01-03 13:22:44 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce4a.jpg" alt = "Select Entropy Pool in menuconfig" / > < / p >
2024-03-29 16:55:46 +08:00
< h1 id = "appendix-build-flash-and-run-nuttx" > < a class = "doc-anchor" href = "#appendix-build-flash-and-run-nuttx" > §< / a > 19 Appendix: Build, Flash and Run NuttX< / h1 >
2021-12-31 19:09:25 +08:00
< p > < em > (For BL602 and ESP32)< / em > < / p >
< p > Below are the steps to build, flash and run NuttX on BL602 and ESP32.< / p >
< p > The instructions below will work on < strong > Linux (Ubuntu)< / strong > , < strong > WSL (Ubuntu)< / strong > and < strong > macOS< / strong > .< / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/quickstart/install.html" > (Instructions for other platforms)< / a > < / p >
< p > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (See this for Arch Linux)< / a > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "build-nuttx" > < a class = "doc-anchor" href = "#build-nuttx" > §< / a > 19.1 Build NuttX< / h2 >
2021-12-31 19:09:25 +08:00
< p > Follow these steps to build NuttX for BL602 or ESP32…< / p >
< ol >
< li >
< p > Install the build prerequisites…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#install-prerequisites" > < strong > “Install Prerequisites”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 10:27:28 +08:00
< p > Assume that we have downloaded the < strong > NuttX Source Code< / strong > and configured the < strong > LoRaWAN Settings< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#download-source-code" > < strong > “Download Source Code”< / strong > < / a > < / p >
2022-01-01 10:27:28 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#device-eui-join-eui-and-app-key" > < strong > “Device EUI, Join EUI and App Key”< / strong > < / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#lorawan-frequency" > < strong > “LoRaWAN Frequency”< / strong > < / a > < / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#build-the-firmware" > < strong > “Build the Firmware”< / strong > < / a > < / p >
< / li >
< li >
< p > To build NuttX, enter this command…< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > make< / code > < / pre > < / div > < / li >
2021-12-31 19:09:25 +08:00
< li >
< p > We should see…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > LD: nuttx
CP: nuttx.hex
2024-12-04 20:02:50 +08:00
CP: nuttx.bin< / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://gist.github.com/lupyuen/8f725c278c25e209c1654469a2855746" > (See the complete log for BL602)< / a > < / p >
< / li >
< li >
2022-02-17 12:18:34 +08:00
< p > < strong > For WSL:< / strong > Copy the < strong > NuttX Firmware< / strong > to the < strong > c:\blflash< / strong > directory in the Windows File System…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > ## /mnt/c/blflash refers to c:\blflash in Windows
2022-02-17 12:18:34 +08:00
mkdir /mnt/c/blflash
2024-12-04 20:02:50 +08:00
cp nuttx.bin /mnt/c/blflash< / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > For WSL we need to run < strong > blflash< / strong > under plain old Windows CMD (not WSL) because it needs to access the COM port.< / p >
< / li >
< li >
< p > In case of problems, refer to the < strong > NuttX Docs< / strong > …< / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/platforms/risc-v/bl602/index.html" > < strong > “BL602 NuttX”< / strong > < / a > < / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/platforms/xtensa/esp32/index.html" > < strong > “ESP32 NuttX”< / strong > < / a > < / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/quickstart/install.html" > < strong > “Installing NuttX”< / strong > < / a > < / p >
< / li >
< / ol >
< blockquote >
< p > < img src = "https://lupyuen.github.io/images/nuttx-build2.png" alt = "Building NuttX" / > < / p >
< / blockquote >
2024-03-29 16:55:46 +08:00
< h2 id = "flash-nuttx" > < a class = "doc-anchor" href = "#flash-nuttx" > §< / a > 19.2 Flash NuttX< / h2 >
2021-12-31 19:09:25 +08:00
< p > < strong > For ESP32:< / strong > < a href = "https://nuttx.apache.org/docs/latest/platforms/xtensa/esp32/index.html#flashing" > < strong > See instructions here< / strong > < / a > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (Also check out this article)< / a > < / p >
< p > < strong > For BL602:< / strong > Follow these steps to install < strong > blflash< / strong > …< / p >
< ol >
< li >
< p > < a href = "https://lupyuen.github.io/articles/flash#install-rustup" > < strong > “Install rustup”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/articles/flash#download-and-build-blflash" > < strong > “Download and build blflash”< / strong > < / a > < / p >
< / li >
< / ol >
< p > We assume that our Firmware Binary File < strong > nuttx.bin< / strong > has been copied to the < strong > blflash< / strong > folder.< / p >
< p > Set BL602 / BL604 to < strong > Flashing Mode< / strong > and restart the board…< / p >
< p > < strong > For PineDio Stack BL604:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > GPIO 8 Jumper< / strong > to < strong > High< / strong > < a href = "https://lupyuen.github.io/images/pinedio-high.jpg" > (Like this)< / a > < / p >
< / li >
< li >
2022-01-26 15:32:42 +08:00
< p > Disconnect the USB cable and reconnect< / p >
2022-01-28 23:27:51 +08:00
< p > Or use the Improvised Reset Button < a href = "https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack" > (Here’ s how)< / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< / ol >
< p > < strong > For PineCone BL602:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > PineCone Jumper (IO 8)< / strong > to the < strong > < code > H< / code > Position< / strong > < a href = "https://lupyuen.github.io/images/pinecone-jumperh.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For BL10:< / strong > < / p >
< ol >
< li >
< p > Connect BL10 to the USB port< / p >
< / li >
< li >
< p > Press and hold the < strong > D8 Button (GPIO 8)< / strong > < / p >
< / li >
< li >
< p > Press and release the < strong > EN Button (Reset)< / strong > < / p >
< / li >
< li >
< p > Release the D8 Button< / p >
< / li >
< / ol >
2022-09-30 12:21:43 +08:00
< p > < strong > For < a href = "https://docs.ai-thinker.com/en/wb2" > Ai-Thinker Ai-WB2< / a > , Pinenut and MagicHome BL602:< / strong > < / p >
2021-12-31 19:09:25 +08:00
< ol >
< li >
< p > Disconnect the board from the USB Port< / p >
< / li >
< li >
< p > Connect < strong > GPIO 8< / strong > to < strong > 3.3V< / strong > < / p >
< / li >
< li >
< p > Reconnect the board to the USB port< / p >
< / li >
< / ol >
< p > Enter these commands to flash < strong > nuttx.bin< / strong > to BL602 / BL604 over UART…< / p >
2023-01-13 07:19:30 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > ## For Linux: Change " /dev/ttyUSB0" to the BL602 / BL604 Serial Port
2022-02-17 12:18:34 +08:00
blflash flash nuttx.bin \
--port /dev/ttyUSB0
2021-12-31 19:09:25 +08:00
2023-01-13 07:19:30 +08:00
## For macOS: Change " /dev/tty.usbserial-1410" to the BL602 / BL604 Serial Port
2022-02-17 12:18:34 +08:00
blflash flash nuttx.bin \
--port /dev/tty.usbserial-1410 \
--initial-baud-rate 230400 \
--baud-rate 230400
2021-12-31 19:09:25 +08:00
2023-01-13 07:19:30 +08:00
## For Windows: Change " COM5" to the BL602 / BL604 Serial Port
2024-12-04 20:02:50 +08:00
blflash flash c:\blflash\nuttx.bin --port COM5< / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://gist.github.com/lupyuen/9c0dbd75bb6b8e810939a36ffb5c399f" > (See the Output Log)< / a > < / p >
< p > For WSL: Do this under plain old Windows CMD (not WSL) because < strong > blflash< / strong > needs to access the COM port.< / p >
2022-11-30 12:01:12 +08:00
< p > < a href = "https://github.com/apache/nuttx/issues/4336" > (Flashing WiFi apps to BL602 / BL604? Remember to use < strong > bl_rfbin< / strong > )< / a > < / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/flash#flash-the-firmware" > (More details on flashing firmware)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/nuttx-flash2.png" alt = "Flashing NuttX" / > < / p >
2024-03-29 16:55:46 +08:00
< h2 id = "run-nuttx" > < a class = "doc-anchor" href = "#run-nuttx" > §< / a > 19.3 Run NuttX< / h2 >
2021-12-31 19:09:25 +08:00
< p > < strong > For ESP32:< / strong > Use Picocom to connect to ESP32 over UART…< / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > picocom -b 115200 /dev/ttyUSB0< / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (More about this)< / a > < / p >
< p > < strong > For BL602:< / strong > Set BL602 / BL604 to < strong > Normal Mode< / strong > (Non-Flashing) and restart the board…< / p >
< p > < strong > For PineDio Stack BL604:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > GPIO 8 Jumper< / strong > to < strong > Low< / strong > < a href = "https://lupyuen.github.io/images/pinedio-low.jpg" > (Like this)< / a > < / p >
< / li >
< li >
2022-01-26 15:32:42 +08:00
< p > Disconnect the USB cable and reconnect< / p >
2022-01-28 23:27:51 +08:00
< p > Or use the Improvised Reset Button < a href = "https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack" > (Here’ s how)< / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< / ol >
< p > < strong > For PineCone BL602:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > PineCone Jumper (IO 8)< / strong > to the < strong > < code > L< / code > Position< / strong > < a href = "https://lupyuen.github.io/images/pinecone-jumperl.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For BL10:< / strong > < / p >
< ol >
< li > Press and release the < strong > EN Button (Reset)< / strong > < / li >
< / ol >
2022-09-30 12:21:43 +08:00
< p > < strong > For < a href = "https://docs.ai-thinker.com/en/wb2" > Ai-Thinker Ai-WB2< / a > , Pinenut and MagicHome BL602:< / strong > < / p >
2021-12-31 19:09:25 +08:00
< ol >
< li >
< p > Disconnect the board from the USB Port< / p >
< / li >
< li >
< p > Connect < strong > GPIO 8< / strong > to < strong > GND< / strong > < / p >
< / li >
< li >
< p > Reconnect the board to the USB port< / p >
< / li >
< / ol >
< p > After restarting, connect to BL602 / BL604’ s UART Port at 2 Mbps like so…< / p >
< p > < strong > For Linux:< / strong > < / p >
2024-12-04 20:02:50 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > screen /dev/ttyUSB0 2000000< / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > < strong > For macOS:< / strong > Use CoolTerm (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > < strong > For Windows:< / strong > Use < code > putty< / code > (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > < strong > Alternatively:< / strong > Use the Web Serial Terminal (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > Press Enter to reveal the < strong > NuttX Shell< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > NuttShell (NSH) NuttX-10.2.0-RC0
2024-12-04 20:02:50 +08:00
nsh> < / code > < / pre > < / div >
2021-12-31 19:09:25 +08:00
< p > Congratulations NuttX is now running on BL602 / BL604!< / p >
< p > < a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > (More details on connecting to BL602 / BL604)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/nuttx-boot2.png" alt = "Running NuttX" / > < / p >
< p > < strong > macOS Tip:< / strong > Here’ s the script I use to build, flash and run NuttX on macOS, all in a single step: < a href = "https://gist.github.com/lupyuen/cc21385ecc66b5c02d15affd776a64af" > run.sh< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/spi2-script.png" alt = "Script to build, flash and run NuttX on macOS" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/cc21385ecc66b5c02d15affd776a64af" > (Source)< / a > < / p >
2021-12-30 16:35:12 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title2.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
2021-12-30 10:58:30 +08:00
2024-02-17 20:10:07 +08:00
<!-- Begin scripts/rustdoc - after.html: Post - HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
<!-- Begin Theme Picker and Prism Theme -->
< script src = "../theme.js" > < / script >
< script src = "../prism.js" > < / script >
<!-- Theme Picker and Prism Theme -->
<!-- End scripts/rustdoc - after.html -->
2021-12-30 10:58:30 +08:00
< / body >
< / html >