NuMaker mbed OS v6.x LoRaWAN

Committer:
cyliang
Date:
Tue Sep 01 20:28:04 2020 +0800
Revision:
0:a160d512fe55
Mbed OS v6.x LoRaWAN example for NuMaker platforms

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cyliang 0:a160d512fe55 1 /**
cyliang 0:a160d512fe55 2 * Copyright (c) 2017, Arm Limited and affiliates.
cyliang 0:a160d512fe55 3 * SPDX-License-Identifier: Apache-2.0
cyliang 0:a160d512fe55 4 *
cyliang 0:a160d512fe55 5 * Licensed under the Apache License, Version 2.0 (the "License");
cyliang 0:a160d512fe55 6 * you may not use this file except in compliance with the License.
cyliang 0:a160d512fe55 7 * You may obtain a copy of the License at
cyliang 0:a160d512fe55 8 *
cyliang 0:a160d512fe55 9 * http://www.apache.org/licenses/LICENSE-2.0
cyliang 0:a160d512fe55 10 *
cyliang 0:a160d512fe55 11 * Unless required by applicable law or agreed to in writing, software
cyliang 0:a160d512fe55 12 * distributed under the License is distributed on an "AS IS" BASIS,
cyliang 0:a160d512fe55 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cyliang 0:a160d512fe55 14 * See the License for the specific language governing permissions and
cyliang 0:a160d512fe55 15 * limitations under the License.
cyliang 0:a160d512fe55 16 */
cyliang 0:a160d512fe55 17 #include <stdio.h>
cyliang 0:a160d512fe55 18
cyliang 0:a160d512fe55 19 #include "lorawan/LoRaWANInterface.h"
cyliang 0:a160d512fe55 20 #include "lorawan/system/lorawan_data_structures.h"
cyliang 0:a160d512fe55 21 #include "events/EventQueue.h"
cyliang 0:a160d512fe55 22
cyliang 0:a160d512fe55 23 // Application helpers
cyliang 0:a160d512fe55 24 #include "DummySensor.h"
cyliang 0:a160d512fe55 25 #include "trace_helper.h"
cyliang 0:a160d512fe55 26 #include "lora_radio_helper.h"
cyliang 0:a160d512fe55 27
cyliang 0:a160d512fe55 28 using namespace events;
cyliang 0:a160d512fe55 29
cyliang 0:a160d512fe55 30 // Max payload size can be LORAMAC_PHY_MAXPAYLOAD.
cyliang 0:a160d512fe55 31 // This example only communicates with much shorter messages (<30 bytes).
cyliang 0:a160d512fe55 32 // If longer messages are used, these buffers must be changed accordingly.
cyliang 0:a160d512fe55 33 uint8_t tx_buffer[30];
cyliang 0:a160d512fe55 34 uint8_t rx_buffer[30];
cyliang 0:a160d512fe55 35
cyliang 0:a160d512fe55 36 /*
cyliang 0:a160d512fe55 37 * Sets up an application dependent transmission timer in ms. Used only when Duty Cycling is off for testing
cyliang 0:a160d512fe55 38 */
cyliang 0:a160d512fe55 39 #define TX_TIMER 10000
cyliang 0:a160d512fe55 40
cyliang 0:a160d512fe55 41 /**
cyliang 0:a160d512fe55 42 * Maximum number of events for the event queue.
cyliang 0:a160d512fe55 43 * 10 is the safe number for the stack events, however, if application
cyliang 0:a160d512fe55 44 * also uses the queue for whatever purposes, this number should be increased.
cyliang 0:a160d512fe55 45 */
cyliang 0:a160d512fe55 46 #define MAX_NUMBER_OF_EVENTS 10
cyliang 0:a160d512fe55 47
cyliang 0:a160d512fe55 48 /**
cyliang 0:a160d512fe55 49 * Maximum number of retries for CONFIRMED messages before giving up
cyliang 0:a160d512fe55 50 */
cyliang 0:a160d512fe55 51 #define CONFIRMED_MSG_RETRY_COUNTER 3
cyliang 0:a160d512fe55 52
cyliang 0:a160d512fe55 53 /**
cyliang 0:a160d512fe55 54 * Dummy pin for dummy sensor
cyliang 0:a160d512fe55 55 */
cyliang 0:a160d512fe55 56 #define PC_9 0
cyliang 0:a160d512fe55 57
cyliang 0:a160d512fe55 58 /**
cyliang 0:a160d512fe55 59 * Dummy sensor class object
cyliang 0:a160d512fe55 60 */
cyliang 0:a160d512fe55 61 DS1820 ds1820(PC_9);
cyliang 0:a160d512fe55 62
cyliang 0:a160d512fe55 63 /**
cyliang 0:a160d512fe55 64 * This event queue is the global event queue for both the
cyliang 0:a160d512fe55 65 * application and stack. To conserve memory, the stack is designed to run
cyliang 0:a160d512fe55 66 * in the same thread as the application and the application is responsible for
cyliang 0:a160d512fe55 67 * providing an event queue to the stack that will be used for ISR deferment as
cyliang 0:a160d512fe55 68 * well as application information event queuing.
cyliang 0:a160d512fe55 69 */
cyliang 0:a160d512fe55 70 static EventQueue ev_queue(MAX_NUMBER_OF_EVENTS *EVENTS_EVENT_SIZE);
cyliang 0:a160d512fe55 71
cyliang 0:a160d512fe55 72 /**
cyliang 0:a160d512fe55 73 * Event handler.
cyliang 0:a160d512fe55 74 *
cyliang 0:a160d512fe55 75 * This will be passed to the LoRaWAN stack to queue events for the
cyliang 0:a160d512fe55 76 * application which in turn drive the application.
cyliang 0:a160d512fe55 77 */
cyliang 0:a160d512fe55 78 static void lora_event_handler(lorawan_event_t event);
cyliang 0:a160d512fe55 79
cyliang 0:a160d512fe55 80 /**
cyliang 0:a160d512fe55 81 * Constructing Mbed LoRaWANInterface and passing it the radio object from lora_radio_helper.
cyliang 0:a160d512fe55 82 */
cyliang 0:a160d512fe55 83 static LoRaWANInterface lorawan(radio);
cyliang 0:a160d512fe55 84
cyliang 0:a160d512fe55 85 /**
cyliang 0:a160d512fe55 86 * Application specific callbacks
cyliang 0:a160d512fe55 87 */
cyliang 0:a160d512fe55 88 static lorawan_app_callbacks_t callbacks;
cyliang 0:a160d512fe55 89
cyliang 0:a160d512fe55 90 /**
cyliang 0:a160d512fe55 91 * Entry point for application
cyliang 0:a160d512fe55 92 */
cyliang 0:a160d512fe55 93 int main(void)
cyliang 0:a160d512fe55 94 {
cyliang 0:a160d512fe55 95 #ifdef MBED_MAJOR_VERSION
cyliang 0:a160d512fe55 96 printf("Mbed OS version %d.%d.%d\r\n\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
cyliang 0:a160d512fe55 97 #endif
cyliang 0:a160d512fe55 98 printf("\n\n Start LoRa testing \r\n");
cyliang 0:a160d512fe55 99 // setup tracing
cyliang 0:a160d512fe55 100 setup_trace();
cyliang 0:a160d512fe55 101
cyliang 0:a160d512fe55 102 // stores the status of a call to LoRaWAN protocol
cyliang 0:a160d512fe55 103 lorawan_status_t retcode;
cyliang 0:a160d512fe55 104
cyliang 0:a160d512fe55 105 // Initialize LoRaWAN stack
cyliang 0:a160d512fe55 106 if (lorawan.initialize(&ev_queue) != LORAWAN_STATUS_OK) {
cyliang 0:a160d512fe55 107 printf("\r\n LoRa initialization failed! \r\n");
cyliang 0:a160d512fe55 108 return -1;
cyliang 0:a160d512fe55 109 }
cyliang 0:a160d512fe55 110
cyliang 0:a160d512fe55 111 printf("\r\n Mbed LoRaWANStack initialized \r\n");
cyliang 0:a160d512fe55 112
cyliang 0:a160d512fe55 113 // prepare application callbacks
cyliang 0:a160d512fe55 114 callbacks.events = mbed::callback(lora_event_handler);
cyliang 0:a160d512fe55 115 lorawan.add_app_callbacks(&callbacks);
cyliang 0:a160d512fe55 116
cyliang 0:a160d512fe55 117 // Set number of retries in case of CONFIRMED messages
cyliang 0:a160d512fe55 118 if (lorawan.set_confirmed_msg_retries(CONFIRMED_MSG_RETRY_COUNTER)
cyliang 0:a160d512fe55 119 != LORAWAN_STATUS_OK) {
cyliang 0:a160d512fe55 120 printf("\r\n set_confirmed_msg_retries failed! \r\n\r\n");
cyliang 0:a160d512fe55 121 return -1;
cyliang 0:a160d512fe55 122 }
cyliang 0:a160d512fe55 123
cyliang 0:a160d512fe55 124 printf("\r\n CONFIRMED message retries : %d \r\n",
cyliang 0:a160d512fe55 125 CONFIRMED_MSG_RETRY_COUNTER);
cyliang 0:a160d512fe55 126
cyliang 0:a160d512fe55 127 // Enable adaptive data rate
cyliang 0:a160d512fe55 128 if (lorawan.enable_adaptive_datarate() != LORAWAN_STATUS_OK) {
cyliang 0:a160d512fe55 129 printf("\r\n enable_adaptive_datarate failed! \r\n");
cyliang 0:a160d512fe55 130 return -1;
cyliang 0:a160d512fe55 131 }
cyliang 0:a160d512fe55 132
cyliang 0:a160d512fe55 133 printf("\r\n Adaptive data rate (ADR) - Enabled \r\n");
cyliang 0:a160d512fe55 134
cyliang 0:a160d512fe55 135 retcode = lorawan.connect();
cyliang 0:a160d512fe55 136
cyliang 0:a160d512fe55 137 if (retcode == LORAWAN_STATUS_OK ||
cyliang 0:a160d512fe55 138 retcode == LORAWAN_STATUS_CONNECT_IN_PROGRESS) {
cyliang 0:a160d512fe55 139 } else {
cyliang 0:a160d512fe55 140 printf("\r\n Connection error, code = %d \r\n", retcode);
cyliang 0:a160d512fe55 141 return -1;
cyliang 0:a160d512fe55 142 }
cyliang 0:a160d512fe55 143
cyliang 0:a160d512fe55 144 printf("\r\n Connection - In Progress ...\r\n");
cyliang 0:a160d512fe55 145
cyliang 0:a160d512fe55 146 // make your event queue dispatching events forever
cyliang 0:a160d512fe55 147 ev_queue.dispatch_forever();
cyliang 0:a160d512fe55 148
cyliang 0:a160d512fe55 149 return 0;
cyliang 0:a160d512fe55 150 }
cyliang 0:a160d512fe55 151
cyliang 0:a160d512fe55 152 /**
cyliang 0:a160d512fe55 153 * Sends a message to the Network Server
cyliang 0:a160d512fe55 154 */
cyliang 0:a160d512fe55 155 static void send_message()
cyliang 0:a160d512fe55 156 {
cyliang 0:a160d512fe55 157 uint16_t packet_len;
cyliang 0:a160d512fe55 158 int16_t retcode;
cyliang 0:a160d512fe55 159 int32_t sensor_value;
cyliang 0:a160d512fe55 160
cyliang 0:a160d512fe55 161 if (ds1820.begin()) {
cyliang 0:a160d512fe55 162 ds1820.startConversion();
cyliang 0:a160d512fe55 163 sensor_value = ds1820.read();
cyliang 0:a160d512fe55 164 printf("\r\n Dummy Sensor Value = %d \r\n", sensor_value);
cyliang 0:a160d512fe55 165 ds1820.startConversion();
cyliang 0:a160d512fe55 166 } else {
cyliang 0:a160d512fe55 167 printf("\r\n No sensor found \r\n");
cyliang 0:a160d512fe55 168 return;
cyliang 0:a160d512fe55 169 }
cyliang 0:a160d512fe55 170
cyliang 0:a160d512fe55 171 packet_len = sprintf((char *) tx_buffer, "Val: %d",
cyliang 0:a160d512fe55 172 sensor_value);
cyliang 0:a160d512fe55 173
cyliang 0:a160d512fe55 174 retcode = lorawan.send(MBED_CONF_LORA_APP_PORT, tx_buffer, packet_len,
cyliang 0:a160d512fe55 175 MSG_UNCONFIRMED_FLAG);
cyliang 0:a160d512fe55 176
cyliang 0:a160d512fe55 177 if (retcode < 0) {
cyliang 0:a160d512fe55 178 retcode == LORAWAN_STATUS_WOULD_BLOCK ? printf("send - WOULD BLOCK\r\n")
cyliang 0:a160d512fe55 179 : printf("\r\n send() - Error code %d \r\n", retcode);
cyliang 0:a160d512fe55 180
cyliang 0:a160d512fe55 181 if (retcode == LORAWAN_STATUS_WOULD_BLOCK) {
cyliang 0:a160d512fe55 182 //retry in 3 seconds
cyliang 0:a160d512fe55 183 if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
cyliang 0:a160d512fe55 184 ev_queue.call_in(3000, send_message);
cyliang 0:a160d512fe55 185 }
cyliang 0:a160d512fe55 186 }
cyliang 0:a160d512fe55 187 return;
cyliang 0:a160d512fe55 188 }
cyliang 0:a160d512fe55 189
cyliang 0:a160d512fe55 190 printf("\r\n %d bytes scheduled for transmission \r\n", retcode);
cyliang 0:a160d512fe55 191 memset(tx_buffer, 0, sizeof(tx_buffer));
cyliang 0:a160d512fe55 192 }
cyliang 0:a160d512fe55 193
cyliang 0:a160d512fe55 194 /**
cyliang 0:a160d512fe55 195 * Receive a message from the Network Server
cyliang 0:a160d512fe55 196 */
cyliang 0:a160d512fe55 197 static void receive_message()
cyliang 0:a160d512fe55 198 {
cyliang 0:a160d512fe55 199 uint8_t port;
cyliang 0:a160d512fe55 200 int flags;
cyliang 0:a160d512fe55 201 int16_t retcode = lorawan.receive(rx_buffer, sizeof(rx_buffer), port, flags);
cyliang 0:a160d512fe55 202
cyliang 0:a160d512fe55 203 if (retcode < 0) {
cyliang 0:a160d512fe55 204 printf("\r\n receive() - Error code %d \r\n", retcode);
cyliang 0:a160d512fe55 205 return;
cyliang 0:a160d512fe55 206 }
cyliang 0:a160d512fe55 207
cyliang 0:a160d512fe55 208 printf(" RX Data on port %u (%d bytes): ", port, retcode);
cyliang 0:a160d512fe55 209 for (uint8_t i = 0; i < retcode; i++) {
cyliang 0:a160d512fe55 210 printf("%02x ", rx_buffer[i]);
cyliang 0:a160d512fe55 211 }
cyliang 0:a160d512fe55 212 printf("\r\n");
cyliang 0:a160d512fe55 213
cyliang 0:a160d512fe55 214 memset(rx_buffer, 0, sizeof(rx_buffer));
cyliang 0:a160d512fe55 215 }
cyliang 0:a160d512fe55 216
cyliang 0:a160d512fe55 217 /**
cyliang 0:a160d512fe55 218 * Event handler
cyliang 0:a160d512fe55 219 */
cyliang 0:a160d512fe55 220 static void lora_event_handler(lorawan_event_t event)
cyliang 0:a160d512fe55 221 {
cyliang 0:a160d512fe55 222 switch (event) {
cyliang 0:a160d512fe55 223 case CONNECTED:
cyliang 0:a160d512fe55 224 printf("\r\n Connection - Successful \r\n");
cyliang 0:a160d512fe55 225 if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
cyliang 0:a160d512fe55 226 send_message();
cyliang 0:a160d512fe55 227 } else {
cyliang 0:a160d512fe55 228 ev_queue.call_every(TX_TIMER, send_message);
cyliang 0:a160d512fe55 229 }
cyliang 0:a160d512fe55 230
cyliang 0:a160d512fe55 231 break;
cyliang 0:a160d512fe55 232 case DISCONNECTED:
cyliang 0:a160d512fe55 233 ev_queue.break_dispatch();
cyliang 0:a160d512fe55 234 printf("\r\n Disconnected Successfully \r\n");
cyliang 0:a160d512fe55 235 break;
cyliang 0:a160d512fe55 236 case TX_DONE:
cyliang 0:a160d512fe55 237 printf("\r\n Message Sent to Network Server \r\n");
cyliang 0:a160d512fe55 238 if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
cyliang 0:a160d512fe55 239 send_message();
cyliang 0:a160d512fe55 240 }
cyliang 0:a160d512fe55 241 break;
cyliang 0:a160d512fe55 242 case TX_TIMEOUT:
cyliang 0:a160d512fe55 243 case TX_ERROR:
cyliang 0:a160d512fe55 244 case TX_CRYPTO_ERROR:
cyliang 0:a160d512fe55 245 case TX_SCHEDULING_ERROR:
cyliang 0:a160d512fe55 246 printf("\r\n Transmission Error - EventCode = %d \r\n", event);
cyliang 0:a160d512fe55 247 // try again
cyliang 0:a160d512fe55 248 if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
cyliang 0:a160d512fe55 249 send_message();
cyliang 0:a160d512fe55 250 }
cyliang 0:a160d512fe55 251 break;
cyliang 0:a160d512fe55 252 case RX_DONE:
cyliang 0:a160d512fe55 253 printf("\r\n Received message from Network Server \r\n");
cyliang 0:a160d512fe55 254 receive_message();
cyliang 0:a160d512fe55 255 break;
cyliang 0:a160d512fe55 256 case RX_TIMEOUT:
cyliang 0:a160d512fe55 257 case RX_ERROR:
cyliang 0:a160d512fe55 258 printf("\r\n Error in reception - Code = %d \r\n", event);
cyliang 0:a160d512fe55 259 break;
cyliang 0:a160d512fe55 260 case JOIN_FAILURE:
cyliang 0:a160d512fe55 261 printf("\r\n OTAA Failed - Check Keys \r\n");
cyliang 0:a160d512fe55 262 break;
cyliang 0:a160d512fe55 263 case UPLINK_REQUIRED:
cyliang 0:a160d512fe55 264 printf("\r\n Uplink required by NS \r\n");
cyliang 0:a160d512fe55 265 if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
cyliang 0:a160d512fe55 266 send_message();
cyliang 0:a160d512fe55 267 }
cyliang 0:a160d512fe55 268 break;
cyliang 0:a160d512fe55 269 default:
cyliang 0:a160d512fe55 270 MBED_ASSERT("Unknown Event");
cyliang 0:a160d512fe55 271 }
cyliang 0:a160d512fe55 272 }
cyliang 0:a160d512fe55 273
cyliang 0:a160d512fe55 274 // EOF