end node on synchronous star LoRa network.

Dependencies:   SX127x sx12xx_hal TSL2561

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

This project for use with LoRaWAN_singlechannel_gateway project.

Alternately gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Network description is at gateway project page. Synchronous star network.

Hardware Support

This project supports SX1276 and SX1272, sx126x kit, sx126x shield, and sx128x 2.4GHz. The ST board B-L072Z-LRWAN1 is also supported (TypeABZ module). When B-L072Z-LRWAN1 target is selected, TARGET_DISCO_L072CZ_LRWAN1 is defined by tools, allowing correct radio driver configuration for this platform. Alternately, any mbed board that can use LoRa radio shield board should work, but NUCLEO boards are tested.

End-node Unique ID

DevEUI is created from CPU serial number. AppEUI and AppKey are declared as software constants.

End-node Configuration

Data rate definition LORAMAC_DEFAULT_DATARATE configured in LoRaMac-definitions.h. See gateway project page for configuration of gateway.
LoRaWAN addressing is configured in Comissioning.h; only OTA mode is functional.
Header file board/lora_config.h, selects application layer options (i.e. sensors) to be compiled in.

Serial Interface

Serial port operates at 115200bps.
Application layer single_us915_main.cpp User button triggers uplink (i.e. blue button on nucleo board), or jumper enables continuously sends repeated uplink packets. The MAC layer holds each uplink request until the allocated timeslot.

commandargumentsdescription
?-print available commands
. (period)-print status (DevEUI, DevAddr, etc)
ullength integerset payload length of test uplink packets

sensor demo

Selected grove sensors may be plugged into SX1272 shield.
To enable, edit lora_config.h to define SENSORS.

Sensor connections on SX1272MB2xAS:

D8 D9: buttonRX TX: (unused)A3 A4: Rotary Angle Sensor
D6 D7: RGB LEDSCL SDA: digital light sensorA1 A2: Rotary Angle Sensor

Digital input pin, state reported via uplink: PC8
Digital output pin, controlled via downlink: PC6
PWM out: PB_10

Jumper enables auto-repeated transmit: PC10 and PC12 on NUCLEO board, located on end of morpho headers nearby JP4.

Committer:
dudmuck
Date:
Sat Jun 17 00:04:30 2017 +0000
Revision:
10:00997daeb0c0
Parent:
7:e238827f0e47
Child:
11:4c337f5bbe4c
add sensor support for grove connectors

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:8f0d0ae0a077 1 /*
dudmuck 0:8f0d0ae0a077 2 / _____) _ | |
dudmuck 0:8f0d0ae0a077 3 ( (____ _____ ____ _| |_ _____ ____| |__
dudmuck 0:8f0d0ae0a077 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
dudmuck 0:8f0d0ae0a077 5 _____) ) ____| | | || |_| ____( (___| | | |
dudmuck 0:8f0d0ae0a077 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
dudmuck 0:8f0d0ae0a077 7 (C)2015 Semtech
dudmuck 0:8f0d0ae0a077 8
dudmuck 0:8f0d0ae0a077 9 Description: LoRaMac classA device implementation
dudmuck 0:8f0d0ae0a077 10
dudmuck 0:8f0d0ae0a077 11 License: Revised BSD License, see LICENSE.TXT file include in the project
dudmuck 0:8f0d0ae0a077 12
dudmuck 0:8f0d0ae0a077 13 Maintainer: Miguel Luis and Gregory Cristian
dudmuck 0:8f0d0ae0a077 14 */
dudmuck 0:8f0d0ae0a077 15 #include "mbed.h"
dudmuck 0:8f0d0ae0a077 16 #include "board.h"
dudmuck 0:8f0d0ae0a077 17 #include "radio.h"
dudmuck 0:8f0d0ae0a077 18
dudmuck 0:8f0d0ae0a077 19 #include "LoRaMac.h"
dudmuck 0:8f0d0ae0a077 20 #include "Commissioning.h"
dudmuck 0:8f0d0ae0a077 21
dudmuck 10:00997daeb0c0 22 #if defined(ENABLE_SX1272) && defined(SENSORS)
dudmuck 10:00997daeb0c0 23 #include "Air_Quality.h"
dudmuck 10:00997daeb0c0 24 AirQuality airqualitysensor;
dudmuck 10:00997daeb0c0 25 PinName analogPin = A1;
dudmuck 10:00997daeb0c0 26 #define SENSOR_PORT 10
dudmuck 10:00997daeb0c0 27 InterruptIn button(D8);
dudmuck 10:00997daeb0c0 28 DigitalOut red_led(D6);
dudmuck 10:00997daeb0c0 29 uint32_t red_cnt;
dudmuck 10:00997daeb0c0 30 #define RED_LED_RATE_US 333333 /* third of second */
dudmuck 10:00997daeb0c0 31 uint32_t button_cnt;
dudmuck 10:00997daeb0c0 32 //AnalogIn water(A3);
dudmuck 10:00997daeb0c0 33 DigitalIn water(A3);
dudmuck 10:00997daeb0c0 34 #endif
dudmuck 10:00997daeb0c0 35
dudmuck 10:00997daeb0c0 36 DigitalOut jumper_out(PC_10);
dudmuck 10:00997daeb0c0 37 InterruptIn jumper_in(PC_12);
dudmuck 10:00997daeb0c0 38
dudmuck 0:8f0d0ae0a077 39 char pcbuf[128];
dudmuck 0:8f0d0ae0a077 40 int pcbuf_len;
dudmuck 0:8f0d0ae0a077 41
dudmuck 0:8f0d0ae0a077 42 /*!
dudmuck 0:8f0d0ae0a077 43 * Defines the application data transmission duty cycle. 5s, value in [ms].
dudmuck 0:8f0d0ae0a077 44 */
dudmuck 0:8f0d0ae0a077 45 #define APP_TX_DUTYCYCLE 5000
dudmuck 0:8f0d0ae0a077 46
dudmuck 0:8f0d0ae0a077 47 /*!
dudmuck 0:8f0d0ae0a077 48 * Defines a random delay for application data transmission duty cycle. 1s,
dudmuck 0:8f0d0ae0a077 49 * value in [ms].
dudmuck 0:8f0d0ae0a077 50 */
dudmuck 0:8f0d0ae0a077 51 #define APP_TX_DUTYCYCLE_RND 1000
dudmuck 0:8f0d0ae0a077 52
dudmuck 0:8f0d0ae0a077 53 /*!
dudmuck 0:8f0d0ae0a077 54 * Default datarate
dudmuck 0:8f0d0ae0a077 55 */
dudmuck 0:8f0d0ae0a077 56 #define LORAWAN_DEFAULT_DATARATE DR_10
dudmuck 0:8f0d0ae0a077 57
dudmuck 0:8f0d0ae0a077 58 /*!
dudmuck 0:8f0d0ae0a077 59 * LoRaWAN confirmed messages
dudmuck 0:8f0d0ae0a077 60 */
dudmuck 0:8f0d0ae0a077 61 #define LORAWAN_CONFIRMED_MSG_ON true
dudmuck 0:8f0d0ae0a077 62
dudmuck 0:8f0d0ae0a077 63 /*!
dudmuck 0:8f0d0ae0a077 64 * LoRaWAN application port
dudmuck 0:8f0d0ae0a077 65 */
dudmuck 0:8f0d0ae0a077 66 #define LORAWAN_APP_PORT 15
dudmuck 0:8f0d0ae0a077 67
dudmuck 0:8f0d0ae0a077 68 /*!
dudmuck 0:8f0d0ae0a077 69 * User application data buffer size
dudmuck 0:8f0d0ae0a077 70 */
dudmuck 0:8f0d0ae0a077 71 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
dudmuck 0:8f0d0ae0a077 72 #define LORAWAN_APP_DATA_SIZE 6
dudmuck 0:8f0d0ae0a077 73
dudmuck 0:8f0d0ae0a077 74 #else
dudmuck 0:8f0d0ae0a077 75 #define LORAWAN_APP_DATA_SIZE 1
dudmuck 0:8f0d0ae0a077 76
dudmuck 0:8f0d0ae0a077 77 #endif
dudmuck 0:8f0d0ae0a077 78
dudmuck 0:8f0d0ae0a077 79 static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
dudmuck 0:8f0d0ae0a077 80 static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
dudmuck 0:8f0d0ae0a077 81 static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
dudmuck 0:8f0d0ae0a077 82
dudmuck 0:8f0d0ae0a077 83 #if( OVER_THE_AIR_ACTIVATION == 0 )
dudmuck 0:8f0d0ae0a077 84
dudmuck 0:8f0d0ae0a077 85 static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
dudmuck 0:8f0d0ae0a077 86 static uint8_t AppSKey[] = LORAWAN_APPSKEY;
dudmuck 0:8f0d0ae0a077 87
dudmuck 0:8f0d0ae0a077 88 /*!
dudmuck 0:8f0d0ae0a077 89 * Device address
dudmuck 0:8f0d0ae0a077 90 */
dudmuck 0:8f0d0ae0a077 91 static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
dudmuck 0:8f0d0ae0a077 92
dudmuck 0:8f0d0ae0a077 93 #endif
dudmuck 0:8f0d0ae0a077 94
dudmuck 0:8f0d0ae0a077 95 /*!
dudmuck 0:8f0d0ae0a077 96 * Application port
dudmuck 0:8f0d0ae0a077 97 */
dudmuck 10:00997daeb0c0 98 #ifdef SENSORS
dudmuck 10:00997daeb0c0 99 static uint8_t AppPort = SENSOR_PORT;
dudmuck 10:00997daeb0c0 100 #else
dudmuck 10:00997daeb0c0 101 static uint8_t AppPort = LORAWAN_APP_PORT;
dudmuck 10:00997daeb0c0 102 #endif
dudmuck 0:8f0d0ae0a077 103
dudmuck 0:8f0d0ae0a077 104 /*!
dudmuck 0:8f0d0ae0a077 105 * User application data size
dudmuck 0:8f0d0ae0a077 106 */
dudmuck 0:8f0d0ae0a077 107 static uint8_t AppDataSize = LORAWAN_APP_DATA_SIZE;
dudmuck 0:8f0d0ae0a077 108 static unsigned int uplink_length; // user assigned
dudmuck 0:8f0d0ae0a077 109
dudmuck 0:8f0d0ae0a077 110 /*!
dudmuck 0:8f0d0ae0a077 111 * User application data buffer size
dudmuck 0:8f0d0ae0a077 112 */
dudmuck 0:8f0d0ae0a077 113 #define LORAWAN_APP_DATA_MAX_SIZE 128
dudmuck 0:8f0d0ae0a077 114
dudmuck 0:8f0d0ae0a077 115 /*!
dudmuck 0:8f0d0ae0a077 116 * User application data
dudmuck 0:8f0d0ae0a077 117 */
dudmuck 0:8f0d0ae0a077 118 static uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE];
dudmuck 0:8f0d0ae0a077 119
dudmuck 0:8f0d0ae0a077 120 /*!
dudmuck 0:8f0d0ae0a077 121 * Indicates if the node is sending confirmed or unconfirmed messages
dudmuck 0:8f0d0ae0a077 122 */
dudmuck 0:8f0d0ae0a077 123 static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
dudmuck 0:8f0d0ae0a077 124
dudmuck 0:8f0d0ae0a077 125 /*!
dudmuck 0:8f0d0ae0a077 126 * Defines the application data transmission duty cycle
dudmuck 0:8f0d0ae0a077 127 */
dudmuck 0:8f0d0ae0a077 128 static uint32_t TxDutyCycleTime;
dudmuck 0:8f0d0ae0a077 129
dudmuck 0:8f0d0ae0a077 130 /*!
dudmuck 0:8f0d0ae0a077 131 * Timer to handle the application data transmission duty cycle
dudmuck 0:8f0d0ae0a077 132 */
dudmuck 0:8f0d0ae0a077 133 LowPowerTimeout TxNextPacketTimer;
dudmuck 0:8f0d0ae0a077 134
dudmuck 0:8f0d0ae0a077 135 volatile bool send_at_beacon;
dudmuck 0:8f0d0ae0a077 136 volatile bool awaiting_mcps_indic;
dudmuck 0:8f0d0ae0a077 137 /*!
dudmuck 0:8f0d0ae0a077 138 * Specifies the state of the application LED
dudmuck 0:8f0d0ae0a077 139 */
dudmuck 0:8f0d0ae0a077 140 static bool AppLedStateOn = false;
dudmuck 0:8f0d0ae0a077 141
dudmuck 0:8f0d0ae0a077 142 /*!
dudmuck 0:8f0d0ae0a077 143 * Indicates if a new packet can be sent
dudmuck 0:8f0d0ae0a077 144 */
dudmuck 0:8f0d0ae0a077 145 static bool NextTx = true;
dudmuck 0:8f0d0ae0a077 146
dudmuck 0:8f0d0ae0a077 147 /*!
dudmuck 0:8f0d0ae0a077 148 * Device states
dudmuck 0:8f0d0ae0a077 149 */
dudmuck 0:8f0d0ae0a077 150 static enum eDeviceState
dudmuck 0:8f0d0ae0a077 151 {
dudmuck 0:8f0d0ae0a077 152 DEVICE_STATE_INIT,
dudmuck 0:8f0d0ae0a077 153 DEVICE_STATE_JOIN,
dudmuck 0:8f0d0ae0a077 154 DEVICE_STATE_SEND,
dudmuck 0:8f0d0ae0a077 155 DEVICE_STATE_CYCLE,
dudmuck 0:8f0d0ae0a077 156 DEVICE_STATE_SLEEP
dudmuck 0:8f0d0ae0a077 157 }DeviceState;
dudmuck 0:8f0d0ae0a077 158
dudmuck 0:8f0d0ae0a077 159 /*!
dudmuck 0:8f0d0ae0a077 160 * Strucure containing the Uplink status
dudmuck 0:8f0d0ae0a077 161 */
dudmuck 0:8f0d0ae0a077 162 struct sLoRaMacUplinkStatus
dudmuck 0:8f0d0ae0a077 163 {
dudmuck 0:8f0d0ae0a077 164 uint8_t Acked;
dudmuck 0:8f0d0ae0a077 165 //int8_t Datarate;
dudmuck 0:8f0d0ae0a077 166 uint16_t UplinkCounter;
dudmuck 0:8f0d0ae0a077 167 uint8_t Port;
dudmuck 0:8f0d0ae0a077 168 uint8_t *Buffer;
dudmuck 0:8f0d0ae0a077 169 uint8_t BufferSize;
dudmuck 0:8f0d0ae0a077 170 }LoRaMacUplinkStatus;
dudmuck 0:8f0d0ae0a077 171 //volatile bool UplinkStatusUpdated = false;
dudmuck 0:8f0d0ae0a077 172
dudmuck 0:8f0d0ae0a077 173 /*!
dudmuck 0:8f0d0ae0a077 174 * Strucure containing the Downlink status
dudmuck 0:8f0d0ae0a077 175 */
dudmuck 0:8f0d0ae0a077 176 struct sLoRaMacDownlinkStatus
dudmuck 0:8f0d0ae0a077 177 {
dudmuck 0:8f0d0ae0a077 178 int16_t Rssi;
dudmuck 0:8f0d0ae0a077 179 int8_t Snr;
dudmuck 0:8f0d0ae0a077 180 uint16_t DownlinkCounter;
dudmuck 0:8f0d0ae0a077 181 bool RxData;
dudmuck 0:8f0d0ae0a077 182 uint8_t Port;
dudmuck 0:8f0d0ae0a077 183 uint8_t *Buffer;
dudmuck 0:8f0d0ae0a077 184 uint8_t BufferSize;
dudmuck 0:8f0d0ae0a077 185 }LoRaMacDownlinkStatus;
dudmuck 0:8f0d0ae0a077 186
dudmuck 2:f2d9aa163652 187 static uint8_t missed_count;
dudmuck 2:f2d9aa163652 188
dudmuck 0:8f0d0ae0a077 189
dudmuck 0:8f0d0ae0a077 190 /*!
dudmuck 0:8f0d0ae0a077 191 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 192 */
dudmuck 0:8f0d0ae0a077 193 static void PrepareTxFrame( uint8_t port )
dudmuck 0:8f0d0ae0a077 194 {
dudmuck 0:8f0d0ae0a077 195 switch( port )
dudmuck 0:8f0d0ae0a077 196 {
dudmuck 0:8f0d0ae0a077 197 case 15:
dudmuck 0:8f0d0ae0a077 198 {
dudmuck 0:8f0d0ae0a077 199 AppData[0] = AppLedStateOn;
dudmuck 0:8f0d0ae0a077 200 if( IsTxConfirmed == true )
dudmuck 0:8f0d0ae0a077 201 {
dudmuck 0:8f0d0ae0a077 202 AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
dudmuck 0:8f0d0ae0a077 203 AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter;
dudmuck 0:8f0d0ae0a077 204 AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8;
dudmuck 0:8f0d0ae0a077 205 AppData[4] = LoRaMacDownlinkStatus.Rssi;
dudmuck 0:8f0d0ae0a077 206 AppData[5] = LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 207 }
dudmuck 0:8f0d0ae0a077 208 }
dudmuck 0:8f0d0ae0a077 209 break;
dudmuck 10:00997daeb0c0 210 #ifdef SENSORS
dudmuck 10:00997daeb0c0 211 case SENSOR_PORT:
dudmuck 10:00997daeb0c0 212 airqualitysensor.slope();
dudmuck 10:00997daeb0c0 213 AppData[0] = airqualitysensor.first_vol >> 8;
dudmuck 10:00997daeb0c0 214 AppData[1] = airqualitysensor.first_vol & 0xff;
dudmuck 10:00997daeb0c0 215 AppDataSize = 2;
dudmuck 10:00997daeb0c0 216 isr_printf("first_vol:%d last_vol:%d\r\n", airqualitysensor.first_vol, airqualitysensor.last_vol);
dudmuck 10:00997daeb0c0 217 break;
dudmuck 10:00997daeb0c0 218 #endif /* SENSORS */
dudmuck 0:8f0d0ae0a077 219 default:
dudmuck 0:8f0d0ae0a077 220 break;
dudmuck 0:8f0d0ae0a077 221 }
dudmuck 0:8f0d0ae0a077 222 }
dudmuck 0:8f0d0ae0a077 223
dudmuck 0:8f0d0ae0a077 224 void
dudmuck 0:8f0d0ae0a077 225 LoRaMacEventInfoStatus_to_string(LoRaMacEventInfoStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 226 {
dudmuck 0:8f0d0ae0a077 227 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 228
dudmuck 0:8f0d0ae0a077 229 switch (status) {
dudmuck 0:8f0d0ae0a077 230 case LORAMAC_EVENT_INFO_STATUS_RX_ERROR: ptr = "RX_ERROR"; break;
dudmuck 0:8f0d0ae0a077 231 case LORAMAC_EVENT_INFO_STATUS_OK: ptr = "OK"; break;
dudmuck 2:f2d9aa163652 232 case LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE: ptr = "ERROR_RX_MTYPE"; break;
dudmuck 2:f2d9aa163652 233 case LORAMAC_EVENT_INFO_STATUS_ERROR_SEND: ptr = "ERROR_SEND"; break;
dudmuck 2:f2d9aa163652 234 case LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT: ptr = "ERROR_JOIN_ACCEPT"; break;
dudmuck 2:f2d9aa163652 235 case LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ: ptr = "ERROR_MLMEREQ"; break;
dudmuck 2:f2d9aa163652 236 case LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ: ptr = "ERROR_MCPSREQ"; break;
dudmuck 2:f2d9aa163652 237 //case LORAMAC_EVENT_INFO_STATUS_ERROR: ptr = "ERROR"; break;
dudmuck 2:f2d9aa163652 238
dudmuck 0:8f0d0ae0a077 239 case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: ptr = "TX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 240 case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT: ptr = "RX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 241 case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL: ptr = "JOIN_FAIL"; break;
dudmuck 0:8f0d0ae0a077 242 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED: ptr = "DOWNLINK_REPEATED"; break;
dudmuck 0:8f0d0ae0a077 243 case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: ptr = "TX_DR_PAYLOAD_SIZE_ERROR"; break;
dudmuck 0:8f0d0ae0a077 244 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS: ptr = "DOWNLINK_TOO_MANY_FRAMES_LOSS"; break;
dudmuck 0:8f0d0ae0a077 245 case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL: ptr = "ADDRESS_FAIL"; break;
dudmuck 0:8f0d0ae0a077 246 case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL: ptr = "MIC_FAIL"; break;
dudmuck 0:8f0d0ae0a077 247 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED: ptr = "BEACON_LOCKED"; break;
dudmuck 0:8f0d0ae0a077 248 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOST: ptr = "BEACON_LOST"; break;
dudmuck 0:8f0d0ae0a077 249 case LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND: ptr = "BEACON_NOT_FOUND"; break;
dudmuck 0:8f0d0ae0a077 250 }
dudmuck 0:8f0d0ae0a077 251
dudmuck 0:8f0d0ae0a077 252 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 253 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 254 }
dudmuck 0:8f0d0ae0a077 255
dudmuck 0:8f0d0ae0a077 256 void
dudmuck 0:8f0d0ae0a077 257 LoRaMacStatus_to_string(LoRaMacStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 258 {
dudmuck 0:8f0d0ae0a077 259 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 260
dudmuck 0:8f0d0ae0a077 261 switch (status) {
dudmuck 0:8f0d0ae0a077 262 case LORAMAC_STATUS_OK: ptr = "OK"; break;
dudmuck 0:8f0d0ae0a077 263 case LORAMAC_STATUS_BUSY: ptr = "BUSY"; break;
dudmuck 0:8f0d0ae0a077 264 case LORAMAC_STATUS_SERVICE_UNKNOWN: ptr = "SERVICE_UNKNOWN"; break;
dudmuck 0:8f0d0ae0a077 265 case LORAMAC_STATUS_PARAMETER_INVALID: ptr = "PARAMETER_INVALID"; break;
dudmuck 0:8f0d0ae0a077 266 case LORAMAC_STATUS_FREQUENCY_INVALID: ptr = "FREQUENCY_INVALID"; break;
dudmuck 0:8f0d0ae0a077 267 case LORAMAC_STATUS_DATARATE_INVALID: ptr = "DATARATE_INVALID"; break;
dudmuck 0:8f0d0ae0a077 268 case LORAMAC_STATUS_FREQ_AND_DR_INVALID: ptr = "FREQ_AND_DR_INVALID"; break;
dudmuck 0:8f0d0ae0a077 269 case LORAMAC_STATUS_NO_NETWORK_JOINED: ptr = "NO_NETWORK_JOINED"; break;
dudmuck 0:8f0d0ae0a077 270 case LORAMAC_STATUS_LENGTH_ERROR: ptr = "LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 271 case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR: ptr = "MAC_CMD_LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 272 case LORAMAC_STATUS_DEVICE_OFF: ptr = "DEVICE_OFF"; break;
dudmuck 0:8f0d0ae0a077 273 }
dudmuck 0:8f0d0ae0a077 274 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 275 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 276 }
dudmuck 0:8f0d0ae0a077 277
dudmuck 0:8f0d0ae0a077 278 /*!
dudmuck 5:c108560af4c3 279 * \brief Function executed on TxNextPacket Timeout event
dudmuck 5:c108560af4c3 280 */
dudmuck 5:c108560af4c3 281 static void OnTxNextPacketTimerEvent( void )
dudmuck 5:c108560af4c3 282 {
dudmuck 5:c108560af4c3 283 MibRequestConfirm_t mibReq;
dudmuck 5:c108560af4c3 284 LoRaMacStatus_t status;
dudmuck 5:c108560af4c3 285
dudmuck 5:c108560af4c3 286 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 5:c108560af4c3 287 status = LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 5:c108560af4c3 288
dudmuck 5:c108560af4c3 289 if( status == LORAMAC_STATUS_OK )
dudmuck 5:c108560af4c3 290 {
dudmuck 5:c108560af4c3 291 if( mibReq.Param.IsNetworkJoined == true )
dudmuck 5:c108560af4c3 292 {
dudmuck 5:c108560af4c3 293 DeviceState = DEVICE_STATE_SEND;
dudmuck 5:c108560af4c3 294 NextTx = true;
dudmuck 5:c108560af4c3 295 }
dudmuck 5:c108560af4c3 296 else
dudmuck 5:c108560af4c3 297 {
dudmuck 5:c108560af4c3 298 DeviceState = DEVICE_STATE_JOIN;
dudmuck 5:c108560af4c3 299 }
dudmuck 5:c108560af4c3 300 }
dudmuck 5:c108560af4c3 301 }
dudmuck 5:c108560af4c3 302
dudmuck 5:c108560af4c3 303 /*!
dudmuck 0:8f0d0ae0a077 304 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 305 *
dudmuck 0:8f0d0ae0a077 306 * \retval [0: frame could be send, 1: error]
dudmuck 0:8f0d0ae0a077 307 */
dudmuck 0:8f0d0ae0a077 308 static bool SendFrame( void )
dudmuck 0:8f0d0ae0a077 309 {
dudmuck 0:8f0d0ae0a077 310 McpsReq_t mcpsReq;
dudmuck 0:8f0d0ae0a077 311 LoRaMacTxInfo_t txInfo;
dudmuck 0:8f0d0ae0a077 312 LoRaMacStatus_t status;
dudmuck 0:8f0d0ae0a077 313 char str[64];
dudmuck 0:8f0d0ae0a077 314
dudmuck 0:8f0d0ae0a077 315 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 316 {
dudmuck 0:8f0d0ae0a077 317 // Send empty frame in order to flush MAC commands
dudmuck 0:8f0d0ae0a077 318 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 319 mcpsReq.Req.Unconfirmed.fBuffer = NULL;
dudmuck 0:8f0d0ae0a077 320 mcpsReq.Req.Unconfirmed.fBufferSize = 0;
dudmuck 0:8f0d0ae0a077 321 //mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 322
dudmuck 0:8f0d0ae0a077 323 LoRaMacUplinkStatus.Acked = false;
dudmuck 0:8f0d0ae0a077 324 LoRaMacUplinkStatus.Port = 0;
dudmuck 0:8f0d0ae0a077 325 LoRaMacUplinkStatus.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 326 LoRaMacUplinkStatus.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 327 }
dudmuck 0:8f0d0ae0a077 328 else
dudmuck 0:8f0d0ae0a077 329 {
dudmuck 0:8f0d0ae0a077 330 LoRaMacUplinkStatus.Acked = false;
dudmuck 0:8f0d0ae0a077 331 LoRaMacUplinkStatus.Port = AppPort;
dudmuck 0:8f0d0ae0a077 332 LoRaMacUplinkStatus.Buffer = AppData;
dudmuck 0:8f0d0ae0a077 333 LoRaMacUplinkStatus.BufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 334
dudmuck 0:8f0d0ae0a077 335 if( IsTxConfirmed == false )
dudmuck 0:8f0d0ae0a077 336 {
dudmuck 0:8f0d0ae0a077 337 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 338 mcpsReq.Req.Unconfirmed.fPort = AppPort;
dudmuck 0:8f0d0ae0a077 339 mcpsReq.Req.Unconfirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 340 mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 341 //mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 342 }
dudmuck 0:8f0d0ae0a077 343 else
dudmuck 0:8f0d0ae0a077 344 {
dudmuck 0:8f0d0ae0a077 345 mcpsReq.Type = MCPS_CONFIRMED;
dudmuck 0:8f0d0ae0a077 346 mcpsReq.Req.Confirmed.fPort = AppPort;
dudmuck 0:8f0d0ae0a077 347 mcpsReq.Req.Confirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 348 mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 349 mcpsReq.Req.Confirmed.NbTrials = 8;
dudmuck 0:8f0d0ae0a077 350 //mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 351 }
dudmuck 0:8f0d0ae0a077 352 }
dudmuck 0:8f0d0ae0a077 353
dudmuck 0:8f0d0ae0a077 354 status = LoRaMacMcpsRequest( &mcpsReq );
dudmuck 0:8f0d0ae0a077 355 if( status == LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 356 {
dudmuck 0:8f0d0ae0a077 357 awaiting_mcps_indic = true;
dudmuck 0:8f0d0ae0a077 358 return false;
dudmuck 0:8f0d0ae0a077 359 }
dudmuck 0:8f0d0ae0a077 360 LoRaMacStatus_to_string(status, str);
dudmuck 1:53c30224eda8 361 isr_printf("send failed:%s\r\n", str);
dudmuck 5:c108560af4c3 362 if (status == LORAMAC_STATUS_NO_NETWORK_JOINED) {
dudmuck 5:c108560af4c3 363 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 5:c108560af4c3 364 }
dudmuck 0:8f0d0ae0a077 365 send_at_beacon = true;
dudmuck 0:8f0d0ae0a077 366 return true;
dudmuck 0:8f0d0ae0a077 367 }
dudmuck 0:8f0d0ae0a077 368
dudmuck 0:8f0d0ae0a077 369
dudmuck 0:8f0d0ae0a077 370 void
dudmuck 0:8f0d0ae0a077 371 send_uplink()
dudmuck 0:8f0d0ae0a077 372 {
dudmuck 0:8f0d0ae0a077 373 AppDataSize = uplink_length;
dudmuck 1:53c30224eda8 374 NextTx = true;
dudmuck 1:53c30224eda8 375 DeviceState = DEVICE_STATE_SEND;
dudmuck 0:8f0d0ae0a077 376 }
dudmuck 0:8f0d0ae0a077 377
dudmuck 0:8f0d0ae0a077 378
dudmuck 0:8f0d0ae0a077 379 /*!
dudmuck 0:8f0d0ae0a077 380 * \brief MCPS-Confirm event function
dudmuck 0:8f0d0ae0a077 381 *
dudmuck 0:8f0d0ae0a077 382 * \param [IN] mcpsConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 383 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 384 */
dudmuck 0:8f0d0ae0a077 385 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
dudmuck 0:8f0d0ae0a077 386 {
dudmuck 2:f2d9aa163652 387 static uint8_t fail_count = 0;
dudmuck 0:8f0d0ae0a077 388 char str[64];
dudmuck 2:f2d9aa163652 389
dudmuck 1:53c30224eda8 390 isr_printf("McpsConfirm ");
dudmuck 0:8f0d0ae0a077 391 if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 392 {
dudmuck 2:f2d9aa163652 393 fail_count = 0;
dudmuck 1:53c30224eda8 394 isr_printf("OK ");
dudmuck 0:8f0d0ae0a077 395 switch( mcpsConfirm->McpsRequest )
dudmuck 0:8f0d0ae0a077 396 {
dudmuck 0:8f0d0ae0a077 397 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 398 {
dudmuck 1:53c30224eda8 399 isr_printf("UNCONFIRMED");
dudmuck 0:8f0d0ae0a077 400 // Check Datarate
dudmuck 0:8f0d0ae0a077 401 // Check TxPower
dudmuck 0:8f0d0ae0a077 402 break;
dudmuck 0:8f0d0ae0a077 403 }
dudmuck 0:8f0d0ae0a077 404 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 405 {
dudmuck 1:53c30224eda8 406 isr_printf("CONFIRMED");
dudmuck 0:8f0d0ae0a077 407 // Check Datarate
dudmuck 0:8f0d0ae0a077 408 // Check TxPower
dudmuck 0:8f0d0ae0a077 409 // Check AckReceived
dudmuck 0:8f0d0ae0a077 410 // Check NbTrials
dudmuck 0:8f0d0ae0a077 411 LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived;
dudmuck 0:8f0d0ae0a077 412 break;
dudmuck 0:8f0d0ae0a077 413 }
dudmuck 0:8f0d0ae0a077 414 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 415 {
dudmuck 0:8f0d0ae0a077 416 break;
dudmuck 0:8f0d0ae0a077 417 }
dudmuck 0:8f0d0ae0a077 418 default:
dudmuck 0:8f0d0ae0a077 419 break;
dudmuck 0:8f0d0ae0a077 420 }
dudmuck 0:8f0d0ae0a077 421 //LoRaMacUplinkStatus.Datarate = mcpsConfirm->Datarate;
dudmuck 0:8f0d0ae0a077 422 LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter;
dudmuck 0:8f0d0ae0a077 423
dudmuck 0:8f0d0ae0a077 424 } else {
dudmuck 0:8f0d0ae0a077 425 LoRaMacEventInfoStatus_to_string(mcpsConfirm->Status, str);
dudmuck 1:53c30224eda8 426 isr_printf("%s ", str);
dudmuck 0:8f0d0ae0a077 427
dudmuck 10:00997daeb0c0 428 //#ifndef MANUAL_UPLINK
dudmuck 0:8f0d0ae0a077 429 /* mcpsIndication may not come. last uplink done, send another uplink */
dudmuck 10:00997daeb0c0 430 if (jumper_in.read()) /* jumper installe: auto uplink */
dudmuck 10:00997daeb0c0 431 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 10:00997daeb0c0 432 //#endif /* !MANUAL_UPLINK */
dudmuck 2:f2d9aa163652 433 if (++fail_count > 10) {
dudmuck 2:f2d9aa163652 434 /* cause re-join */
dudmuck 2:f2d9aa163652 435 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 436 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 2:f2d9aa163652 437 mibReq.Param.IsNetworkJoined = false;
dudmuck 2:f2d9aa163652 438 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 2:f2d9aa163652 439 }
dudmuck 0:8f0d0ae0a077 440 }
dudmuck 0:8f0d0ae0a077 441
dudmuck 0:8f0d0ae0a077 442 NextTx = true;
dudmuck 1:53c30224eda8 443 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 444 }
dudmuck 0:8f0d0ae0a077 445
dudmuck 10:00997daeb0c0 446 #ifdef SENSORS
dudmuck 10:00997daeb0c0 447 void red_led_cb()
dudmuck 10:00997daeb0c0 448 {
dudmuck 10:00997daeb0c0 449 red_led = !red_led;
dudmuck 10:00997daeb0c0 450
dudmuck 10:00997daeb0c0 451 if (red_cnt > 0 || red_led.read()) {
dudmuck 10:00997daeb0c0 452 TxNextPacketTimer.attach_us(&red_led_cb, RED_LED_RATE_US);
dudmuck 10:00997daeb0c0 453 if (red_led.read()) /* only decrement on falling edge */
dudmuck 10:00997daeb0c0 454 red_cnt--;
dudmuck 10:00997daeb0c0 455 }
dudmuck 10:00997daeb0c0 456 }
dudmuck 10:00997daeb0c0 457 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 458
dudmuck 0:8f0d0ae0a077 459 /*!
dudmuck 0:8f0d0ae0a077 460 * \brief MCPS-Indication event function
dudmuck 0:8f0d0ae0a077 461 *
dudmuck 0:8f0d0ae0a077 462 * \param [IN] mcpsIndication - Pointer to the indication structure,
dudmuck 0:8f0d0ae0a077 463 * containing indication attributes.
dudmuck 0:8f0d0ae0a077 464 */
dudmuck 0:8f0d0ae0a077 465 static void McpsIndication( McpsIndication_t *mcpsIndication )
dudmuck 0:8f0d0ae0a077 466 {
dudmuck 1:53c30224eda8 467 isr_printf("McpsIndication ");
dudmuck 0:8f0d0ae0a077 468
dudmuck 10:00997daeb0c0 469 //#ifndef MANUAL_UPLINK
dudmuck 0:8f0d0ae0a077 470 /* last uplink done, send another uplink */
dudmuck 10:00997daeb0c0 471 if (jumper_in.read()) /* jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 472 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 10:00997daeb0c0 473 //#endif /* !MANUAL_UPLINK */
dudmuck 0:8f0d0ae0a077 474
dudmuck 0:8f0d0ae0a077 475 if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 476 {
dudmuck 10:00997daeb0c0 477 isr_printf("!ok\r\n");
dudmuck 0:8f0d0ae0a077 478 return;
dudmuck 0:8f0d0ae0a077 479 }
dudmuck 0:8f0d0ae0a077 480
dudmuck 0:8f0d0ae0a077 481 awaiting_mcps_indic = false;
dudmuck 10:00997daeb0c0 482 #ifdef SENSORS
dudmuck 10:00997daeb0c0 483 red_led = 0;
dudmuck 10:00997daeb0c0 484 #endif /* SENSORS */
dudmuck 0:8f0d0ae0a077 485
dudmuck 0:8f0d0ae0a077 486 switch( mcpsIndication->McpsIndication )
dudmuck 0:8f0d0ae0a077 487 {
dudmuck 5:c108560af4c3 488 /* this refers to the downlink from gateway, not the uplink that was sent to it */
dudmuck 0:8f0d0ae0a077 489 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 490 {
dudmuck 1:53c30224eda8 491 isr_printf("UNCONFIRMED ");
dudmuck 0:8f0d0ae0a077 492 break;
dudmuck 0:8f0d0ae0a077 493 }
dudmuck 0:8f0d0ae0a077 494 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 495 {
dudmuck 5:c108560af4c3 496 /* downlink has requested Ack */
dudmuck 1:53c30224eda8 497 isr_printf("CONFIRMED ");
dudmuck 0:8f0d0ae0a077 498 break;
dudmuck 0:8f0d0ae0a077 499 }
dudmuck 0:8f0d0ae0a077 500 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 501 {
dudmuck 0:8f0d0ae0a077 502 break;
dudmuck 0:8f0d0ae0a077 503 }
dudmuck 0:8f0d0ae0a077 504 case MCPS_MULTICAST:
dudmuck 0:8f0d0ae0a077 505 {
dudmuck 10:00997daeb0c0 506 isr_printf("MCPS_MULTICAST ");
dudmuck 10:00997daeb0c0 507 if (mcpsIndication->RxData) {
dudmuck 10:00997daeb0c0 508 isr_printf("beacon-rxdata");
dudmuck 10:00997daeb0c0 509 #ifdef SENSORS
dudmuck 10:00997daeb0c0 510 red_cnt = mcpsIndication->Buffer[0] - 1;
dudmuck 10:00997daeb0c0 511 red_led = 1;
dudmuck 10:00997daeb0c0 512 TxNextPacketTimer.attach_us(&red_led_cb, RED_LED_RATE_US);
dudmuck 10:00997daeb0c0 513 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 514 }
dudmuck 0:8f0d0ae0a077 515 break;
dudmuck 0:8f0d0ae0a077 516 }
dudmuck 0:8f0d0ae0a077 517 default:
dudmuck 0:8f0d0ae0a077 518 break;
dudmuck 0:8f0d0ae0a077 519 }
dudmuck 0:8f0d0ae0a077 520
dudmuck 0:8f0d0ae0a077 521 // Check Multicast
dudmuck 0:8f0d0ae0a077 522 // Check Port
dudmuck 0:8f0d0ae0a077 523 // Check Datarate
dudmuck 0:8f0d0ae0a077 524 // Check FramePending
dudmuck 0:8f0d0ae0a077 525 // Check Buffer
dudmuck 0:8f0d0ae0a077 526 // Check BufferSize
dudmuck 0:8f0d0ae0a077 527 // Check Rssi
dudmuck 0:8f0d0ae0a077 528 // Check Snr
dudmuck 0:8f0d0ae0a077 529 // Check RxSlot
dudmuck 0:8f0d0ae0a077 530 LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi;
dudmuck 0:8f0d0ae0a077 531 if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
dudmuck 0:8f0d0ae0a077 532 {
dudmuck 0:8f0d0ae0a077 533 // Invert and divide by 4
dudmuck 0:8f0d0ae0a077 534 LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 535 LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 536 }
dudmuck 0:8f0d0ae0a077 537 else
dudmuck 0:8f0d0ae0a077 538 {
dudmuck 0:8f0d0ae0a077 539 // Divide by 4
dudmuck 0:8f0d0ae0a077 540 LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 541 }
dudmuck 0:8f0d0ae0a077 542 LoRaMacDownlinkStatus.DownlinkCounter++;
dudmuck 0:8f0d0ae0a077 543 LoRaMacDownlinkStatus.RxData = mcpsIndication->RxData;
dudmuck 0:8f0d0ae0a077 544 LoRaMacDownlinkStatus.Port = mcpsIndication->Port;
dudmuck 0:8f0d0ae0a077 545 LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer;
dudmuck 0:8f0d0ae0a077 546 LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize;
dudmuck 0:8f0d0ae0a077 547
dudmuck 0:8f0d0ae0a077 548 if( mcpsIndication->RxData == true )
dudmuck 0:8f0d0ae0a077 549 {
dudmuck 0:8f0d0ae0a077 550 int i;
dudmuck 1:53c30224eda8 551 isr_printf("RxData %u ", mcpsIndication->BufferSize);
dudmuck 0:8f0d0ae0a077 552 for (i = 0; i < mcpsIndication->BufferSize; i++) {
dudmuck 1:53c30224eda8 553 isr_printf("%02x ", mcpsIndication->Buffer[i]);
dudmuck 0:8f0d0ae0a077 554 }
dudmuck 1:53c30224eda8 555 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 556
dudmuck 0:8f0d0ae0a077 557 switch( mcpsIndication->Port )
dudmuck 0:8f0d0ae0a077 558 {
dudmuck 0:8f0d0ae0a077 559 case 1: // The application LED can be controlled on port 1 or 2
dudmuck 0:8f0d0ae0a077 560 case 2:
dudmuck 0:8f0d0ae0a077 561 if( mcpsIndication->BufferSize == 1 )
dudmuck 0:8f0d0ae0a077 562 {
dudmuck 0:8f0d0ae0a077 563 AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
dudmuck 0:8f0d0ae0a077 564 //Led3StateChanged = true;
dudmuck 0:8f0d0ae0a077 565 }
dudmuck 0:8f0d0ae0a077 566 break;
dudmuck 0:8f0d0ae0a077 567 default:
dudmuck 0:8f0d0ae0a077 568 break;
dudmuck 0:8f0d0ae0a077 569 }
dudmuck 0:8f0d0ae0a077 570 }
dudmuck 0:8f0d0ae0a077 571
dudmuck 1:53c30224eda8 572 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 573 }
dudmuck 0:8f0d0ae0a077 574
dudmuck 0:8f0d0ae0a077 575 /*!
dudmuck 0:8f0d0ae0a077 576 * \brief MLME-Confirm event function
dudmuck 0:8f0d0ae0a077 577 *
dudmuck 0:8f0d0ae0a077 578 * \param [IN] mlmeConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 579 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 580 */
dudmuck 0:8f0d0ae0a077 581 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
dudmuck 0:8f0d0ae0a077 582 {
dudmuck 1:53c30224eda8 583 isr_printf("MlmeConfirm ");
dudmuck 0:8f0d0ae0a077 584 switch( mlmeConfirm->MlmeRequest )
dudmuck 0:8f0d0ae0a077 585 {
dudmuck 0:8f0d0ae0a077 586 case MLME_JOIN:
dudmuck 0:8f0d0ae0a077 587 {
dudmuck 1:53c30224eda8 588 isr_printf("MLME_JOIN ");
dudmuck 10:00997daeb0c0 589 #ifdef SENSORS
dudmuck 10:00997daeb0c0 590 red_led = 0;
dudmuck 10:00997daeb0c0 591 #endif /* SENSORS */
dudmuck 0:8f0d0ae0a077 592 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 593 {
dudmuck 0:8f0d0ae0a077 594 // Status is OK, node has joined the network
dudmuck 0:8f0d0ae0a077 595 //DeviceState = DEVICE_STATE_SEND;
dudmuck 0:8f0d0ae0a077 596 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 1:53c30224eda8 597 isr_printf("ok");
dudmuck 2:f2d9aa163652 598 missed_count = 0;
dudmuck 0:8f0d0ae0a077 599 }
dudmuck 0:8f0d0ae0a077 600 else
dudmuck 0:8f0d0ae0a077 601 {
dudmuck 0:8f0d0ae0a077 602 // Join was not successful. Try to join again
dudmuck 0:8f0d0ae0a077 603 DeviceState = DEVICE_STATE_JOIN;
dudmuck 1:53c30224eda8 604 isr_printf("fail");
dudmuck 0:8f0d0ae0a077 605 }
dudmuck 0:8f0d0ae0a077 606 break;
dudmuck 0:8f0d0ae0a077 607 }
dudmuck 0:8f0d0ae0a077 608 case MLME_LINK_CHECK:
dudmuck 0:8f0d0ae0a077 609 {
dudmuck 1:53c30224eda8 610 isr_printf("LINK_CHECK");
dudmuck 0:8f0d0ae0a077 611 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 612 {
dudmuck 0:8f0d0ae0a077 613 // Check DemodMargin
dudmuck 0:8f0d0ae0a077 614 //mlmeConfirm->DemodMargin;
dudmuck 0:8f0d0ae0a077 615 // Check NbGateways
dudmuck 0:8f0d0ae0a077 616 //mlmeConfirm->NbGateways;
dudmuck 0:8f0d0ae0a077 617 }
dudmuck 0:8f0d0ae0a077 618 break;
dudmuck 0:8f0d0ae0a077 619 }
dudmuck 0:8f0d0ae0a077 620 default:
dudmuck 0:8f0d0ae0a077 621 break;
dudmuck 0:8f0d0ae0a077 622 }
dudmuck 0:8f0d0ae0a077 623 NextTx = true;
dudmuck 1:53c30224eda8 624 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 625 }
dudmuck 0:8f0d0ae0a077 626
dudmuck 0:8f0d0ae0a077 627
dudmuck 0:8f0d0ae0a077 628 static void MlmeIndication( MlmeIndication_t *MlmeIndication )
dudmuck 0:8f0d0ae0a077 629 {
dudmuck 0:8f0d0ae0a077 630 char str[64];
dudmuck 0:8f0d0ae0a077 631 //MibRequestConfirm_t mibReq;
dudmuck 0:8f0d0ae0a077 632
dudmuck 1:53c30224eda8 633 isr_printf("MlmeIndication ");
dudmuck 0:8f0d0ae0a077 634 switch( MlmeIndication->MlmeIndication )
dudmuck 0:8f0d0ae0a077 635 {
dudmuck 0:8f0d0ae0a077 636 case MLME_BEACON:
dudmuck 0:8f0d0ae0a077 637 {
dudmuck 2:f2d9aa163652 638 isr_printf("missed:%u BEACON ", missed_count);
dudmuck 0:8f0d0ae0a077 639 LoRaMacEventInfoStatus_to_string(MlmeIndication->Status, str);
dudmuck 1:53c30224eda8 640 isr_printf("%s ", str);
dudmuck 10:00997daeb0c0 641 //#ifndef MANUAL_UPLINK
dudmuck 0:8f0d0ae0a077 642 if (send_at_beacon) {
dudmuck 0:8f0d0ae0a077 643 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 0:8f0d0ae0a077 644 send_at_beacon = false;
dudmuck 0:8f0d0ae0a077 645 }
dudmuck 10:00997daeb0c0 646 //#endif /* !MANUAL_UPLINK */
dudmuck 2:f2d9aa163652 647 if (LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED == MlmeIndication->Status)
dudmuck 2:f2d9aa163652 648 missed_count = 0;
dudmuck 2:f2d9aa163652 649 else if (++missed_count > 4) {
dudmuck 2:f2d9aa163652 650 /* cause re-join */
dudmuck 2:f2d9aa163652 651 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 652 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 2:f2d9aa163652 653 mibReq.Param.IsNetworkJoined = false;
dudmuck 2:f2d9aa163652 654 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 2:f2d9aa163652 655 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 2:f2d9aa163652 656 }
dudmuck 0:8f0d0ae0a077 657 break;
dudmuck 0:8f0d0ae0a077 658
dudmuck 0:8f0d0ae0a077 659 }
dudmuck 10:00997daeb0c0 660 case MLME_TXDONE:
dudmuck 10:00997daeb0c0 661 isr_printf("MLME_TXDONE ");
dudmuck 10:00997daeb0c0 662 #ifdef SENSORS
dudmuck 10:00997daeb0c0 663 red_led = 1;
dudmuck 10:00997daeb0c0 664 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 665 break;
dudmuck 0:8f0d0ae0a077 666 default:
dudmuck 1:53c30224eda8 667 isr_printf("<%d> ", MlmeIndication->MlmeIndication);
dudmuck 0:8f0d0ae0a077 668 break;
dudmuck 0:8f0d0ae0a077 669 }
dudmuck 0:8f0d0ae0a077 670
dudmuck 1:53c30224eda8 671 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 672 }
dudmuck 0:8f0d0ae0a077 673
dudmuck 0:8f0d0ae0a077 674 void
dudmuck 0:8f0d0ae0a077 675 send_pcbuf_uplink()
dudmuck 0:8f0d0ae0a077 676 {
dudmuck 0:8f0d0ae0a077 677 bool ret;
dudmuck 0:8f0d0ae0a077 678 memcpy(AppData, pcbuf, pcbuf_len);
dudmuck 0:8f0d0ae0a077 679 AppDataSize = pcbuf_len;
dudmuck 0:8f0d0ae0a077 680
dudmuck 0:8f0d0ae0a077 681 ret = SendFrame( );
dudmuck 1:53c30224eda8 682 isr_printf("%d = SendFrame()\r\n", ret);
dudmuck 0:8f0d0ae0a077 683 }
dudmuck 0:8f0d0ae0a077 684
dudmuck 10:00997daeb0c0 685
dudmuck 0:8f0d0ae0a077 686 void cmd_status(uint8_t idx)
dudmuck 0:8f0d0ae0a077 687 {
dudmuck 2:f2d9aa163652 688 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 689
dudmuck 2:f2d9aa163652 690 isr_printf("DevEUI ");
dudmuck 2:f2d9aa163652 691 for (int i = 0; i < 8; i++)
dudmuck 2:f2d9aa163652 692 isr_printf("%02x ", DevEui[i]);
dudmuck 2:f2d9aa163652 693 mibReq.Type = MIB_DEV_ADDR;
dudmuck 2:f2d9aa163652 694 LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 2:f2d9aa163652 695 isr_printf(", DevAddr:%x\r\n", mibReq.Param.DevAddr);
dudmuck 2:f2d9aa163652 696
dudmuck 10:00997daeb0c0 697 #ifdef SENSORS
dudmuck 10:00997daeb0c0 698 //printf("button:%d,%u water:%f ", button.read(), button_cnt, water.read());
dudmuck 10:00997daeb0c0 699 printf("button:%d,%u water:%d jumper:%d ", button.read(), button_cnt, water.read(), jumper_in.read());
dudmuck 10:00997daeb0c0 700 #endif
dudmuck 1:53c30224eda8 701 isr_printf("DeviceState:%d\r\n", DeviceState);
dudmuck 1:53c30224eda8 702 isr_printf("send_at_beacon:%d\r\n", send_at_beacon);
dudmuck 1:53c30224eda8 703 isr_printf("awaiting_mcps_indic:%d\r\n", awaiting_mcps_indic);
dudmuck 0:8f0d0ae0a077 704 loramac_print_status();
dudmuck 10:00997daeb0c0 705
dudmuck 0:8f0d0ae0a077 706 }
dudmuck 0:8f0d0ae0a077 707
dudmuck 0:8f0d0ae0a077 708 void cmd_uplink_length(uint8_t idx)
dudmuck 0:8f0d0ae0a077 709 {
dudmuck 0:8f0d0ae0a077 710 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:8f0d0ae0a077 711 sscanf(pcbuf+idx, "%u", &uplink_length);
dudmuck 0:8f0d0ae0a077 712 }
dudmuck 1:53c30224eda8 713 isr_printf("uplink_length:%u\r\n", uplink_length);
dudmuck 0:8f0d0ae0a077 714 }
dudmuck 0:8f0d0ae0a077 715
dudmuck 10:00997daeb0c0 716 #ifdef SENSORS
dudmuck 10:00997daeb0c0 717 void cmd_sensor(uint8_t idx)
dudmuck 10:00997daeb0c0 718 {
dudmuck 10:00997daeb0c0 719 int current_quality = airqualitysensor.slope();
dudmuck 10:00997daeb0c0 720 if (current_quality >= 0) { // if a valid data returned.
dudmuck 10:00997daeb0c0 721 if (current_quality == 0)
dudmuck 10:00997daeb0c0 722 isr_printf("High pollution! Force signal active\n\r");
dudmuck 10:00997daeb0c0 723 else if (current_quality == 1)
dudmuck 10:00997daeb0c0 724 isr_printf("High pollution!\n\r");
dudmuck 10:00997daeb0c0 725 else if (current_quality == 2)
dudmuck 10:00997daeb0c0 726 isr_printf("Low pollution!\n\r");
dudmuck 10:00997daeb0c0 727 else if (current_quality == 3)
dudmuck 10:00997daeb0c0 728 isr_printf("Fresh air\n\r");
dudmuck 10:00997daeb0c0 729 }
dudmuck 10:00997daeb0c0 730 }
dudmuck 10:00997daeb0c0 731
dudmuck 10:00997daeb0c0 732 void cmd_red_led(uint8_t idx)
dudmuck 10:00997daeb0c0 733 {
dudmuck 10:00997daeb0c0 734 red_led = !red_led;
dudmuck 10:00997daeb0c0 735 printf("red_led:%u\r\n", red_led.read());
dudmuck 10:00997daeb0c0 736 }
dudmuck 10:00997daeb0c0 737
dudmuck 10:00997daeb0c0 738 void cmd_water_pull(uint8_t idx)
dudmuck 10:00997daeb0c0 739 {
dudmuck 10:00997daeb0c0 740 printf("water pull:");
dudmuck 10:00997daeb0c0 741 if (pcbuf[idx] == 'u') {
dudmuck 10:00997daeb0c0 742 water.mode(PullUp);
dudmuck 10:00997daeb0c0 743 printf("up");
dudmuck 10:00997daeb0c0 744 }else if (pcbuf[idx] == 'n') {
dudmuck 10:00997daeb0c0 745 water.mode(PullNone);
dudmuck 10:00997daeb0c0 746 printf("none");
dudmuck 10:00997daeb0c0 747 } else if (pcbuf[idx] == 'd') {
dudmuck 10:00997daeb0c0 748 water.mode(PullDown);
dudmuck 10:00997daeb0c0 749 printf("down");
dudmuck 10:00997daeb0c0 750 } else if (pcbuf[idx] == 'o') {
dudmuck 10:00997daeb0c0 751 water.mode(OpenDrain);
dudmuck 10:00997daeb0c0 752 printf("od");
dudmuck 10:00997daeb0c0 753 }
dudmuck 10:00997daeb0c0 754 printf("\r\n");
dudmuck 10:00997daeb0c0 755 }
dudmuck 10:00997daeb0c0 756
dudmuck 10:00997daeb0c0 757 void cmd_led_flash(uint8_t idx)
dudmuck 10:00997daeb0c0 758 {
dudmuck 10:00997daeb0c0 759 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 10:00997daeb0c0 760 sscanf(pcbuf+idx, "%u", &red_cnt);
dudmuck 10:00997daeb0c0 761 if (red_cnt > 0) {
dudmuck 10:00997daeb0c0 762 red_cnt--;
dudmuck 10:00997daeb0c0 763 red_led = 1;
dudmuck 10:00997daeb0c0 764 TxNextPacketTimer.attach_us(&red_led_cb, RED_LED_RATE_US);
dudmuck 10:00997daeb0c0 765 }
dudmuck 10:00997daeb0c0 766 }
dudmuck 10:00997daeb0c0 767 }
dudmuck 10:00997daeb0c0 768 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 769
dudmuck 0:8f0d0ae0a077 770 typedef struct {
dudmuck 0:8f0d0ae0a077 771 const char* const cmd;
dudmuck 0:8f0d0ae0a077 772 void (*handler)(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 773 const char* const arg_descr;
dudmuck 0:8f0d0ae0a077 774 const char* const description;
dudmuck 0:8f0d0ae0a077 775 } menu_item_t;
dudmuck 0:8f0d0ae0a077 776
dudmuck 0:8f0d0ae0a077 777 void cmd_help(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 778
dudmuck 0:8f0d0ae0a077 779 const menu_item_t menu_items[] =
dudmuck 0:8f0d0ae0a077 780 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:8f0d0ae0a077 781 { "?", cmd_help, "","show available commands"},
dudmuck 0:8f0d0ae0a077 782 { ".", cmd_status, "","print status"},
dudmuck 10:00997daeb0c0 783 { "ul", cmd_uplink_length, "%u","set uplink payload length"},
dudmuck 10:00997daeb0c0 784 #ifdef SENSORS
dudmuck 10:00997daeb0c0 785 { "s", cmd_sensor, "","read sensor"},
dudmuck 10:00997daeb0c0 786 { "l", cmd_red_led, "","toggle red LED"},
dudmuck 10:00997daeb0c0 787 { "w", cmd_water_pull, "%c","config water pull: u,d,n,o"},
dudmuck 10:00997daeb0c0 788 { "f", cmd_led_flash, "%d","flash LED n times"},
dudmuck 10:00997daeb0c0 789 #endif
dudmuck 0:8f0d0ae0a077 790 { NULL, NULL, NULL, NULL }
dudmuck 0:8f0d0ae0a077 791 };
dudmuck 0:8f0d0ae0a077 792
dudmuck 0:8f0d0ae0a077 793 void cmd_help(uint8_t args_at)
dudmuck 0:8f0d0ae0a077 794 {
dudmuck 0:8f0d0ae0a077 795 int i;
dudmuck 0:8f0d0ae0a077 796
dudmuck 0:8f0d0ae0a077 797 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 1:53c30224eda8 798 isr_printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:8f0d0ae0a077 799 }
dudmuck 0:8f0d0ae0a077 800
dudmuck 0:8f0d0ae0a077 801 }
dudmuck 0:8f0d0ae0a077 802
dudmuck 0:8f0d0ae0a077 803 void
dudmuck 0:8f0d0ae0a077 804 console()
dudmuck 0:8f0d0ae0a077 805 {
dudmuck 0:8f0d0ae0a077 806 bool parsed;
dudmuck 0:8f0d0ae0a077 807 int i;
dudmuck 0:8f0d0ae0a077 808 uint8_t user_cmd_len;
dudmuck 0:8f0d0ae0a077 809
dudmuck 0:8f0d0ae0a077 810 if (pcbuf_len < 0) { // ctrl-C
dudmuck 1:53c30224eda8 811 //isr_printf("abort\r\n");
dudmuck 0:8f0d0ae0a077 812 return;
dudmuck 0:8f0d0ae0a077 813 }
dudmuck 0:8f0d0ae0a077 814 if (pcbuf_len == 0)
dudmuck 0:8f0d0ae0a077 815 return;
dudmuck 0:8f0d0ae0a077 816
dudmuck 1:53c30224eda8 817 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 818
dudmuck 0:8f0d0ae0a077 819 /* get end of user-entered command */
dudmuck 0:8f0d0ae0a077 820 user_cmd_len = 1; // first character can be any character
dudmuck 0:8f0d0ae0a077 821 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:8f0d0ae0a077 822 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:8f0d0ae0a077 823 user_cmd_len = i;
dudmuck 0:8f0d0ae0a077 824 break;
dudmuck 0:8f0d0ae0a077 825 }
dudmuck 0:8f0d0ae0a077 826 }
dudmuck 0:8f0d0ae0a077 827
dudmuck 0:8f0d0ae0a077 828 parsed = false;
dudmuck 0:8f0d0ae0a077 829 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:8f0d0ae0a077 830 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:8f0d0ae0a077 831
dudmuck 0:8f0d0ae0a077 832 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:8f0d0ae0a077 833 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:8f0d0ae0a077 834 mi_len++;
dudmuck 0:8f0d0ae0a077 835 menu_items[i].handler(mi_len);
dudmuck 0:8f0d0ae0a077 836 parsed = true;
dudmuck 0:8f0d0ae0a077 837 break;
dudmuck 0:8f0d0ae0a077 838 }
dudmuck 0:8f0d0ae0a077 839 }
dudmuck 0:8f0d0ae0a077 840
dudmuck 0:8f0d0ae0a077 841 if (!parsed)
dudmuck 0:8f0d0ae0a077 842 send_pcbuf_uplink();
dudmuck 0:8f0d0ae0a077 843
dudmuck 0:8f0d0ae0a077 844 pcbuf_len = 0;
dudmuck 1:53c30224eda8 845 isr_printf("> ");
dudmuck 0:8f0d0ae0a077 846 fflush(stdout);
dudmuck 0:8f0d0ae0a077 847 }
dudmuck 0:8f0d0ae0a077 848
dudmuck 0:8f0d0ae0a077 849 void rx_callback()
dudmuck 0:8f0d0ae0a077 850 {
dudmuck 0:8f0d0ae0a077 851 static uint8_t pcbuf_idx = 0;
dudmuck 0:8f0d0ae0a077 852 static uint8_t prev_len = 0;;
dudmuck 0:8f0d0ae0a077 853 char c = pc.getc();
dudmuck 0:8f0d0ae0a077 854
dudmuck 0:8f0d0ae0a077 855 if (c == 8) {
dudmuck 0:8f0d0ae0a077 856 if (pcbuf_idx > 0) {
dudmuck 0:8f0d0ae0a077 857 pc.putc(8);
dudmuck 0:8f0d0ae0a077 858 pc.putc(' ');
dudmuck 0:8f0d0ae0a077 859 pc.putc(8);
dudmuck 0:8f0d0ae0a077 860 pcbuf_idx--;
dudmuck 0:8f0d0ae0a077 861 }
dudmuck 0:8f0d0ae0a077 862 } else if (c == 3) { // ctrl-C
dudmuck 0:8f0d0ae0a077 863 pcbuf_len = -1;
dudmuck 0:8f0d0ae0a077 864 } else if (c == '\r') {
dudmuck 0:8f0d0ae0a077 865 if (pcbuf_idx == 0) {
dudmuck 0:8f0d0ae0a077 866 pcbuf_len = prev_len;
dudmuck 0:8f0d0ae0a077 867 } else {
dudmuck 0:8f0d0ae0a077 868 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:8f0d0ae0a077 869 prev_len = pcbuf_idx;
dudmuck 0:8f0d0ae0a077 870 pcbuf_idx = 0;
dudmuck 0:8f0d0ae0a077 871 pcbuf_len = prev_len;
dudmuck 0:8f0d0ae0a077 872 }
dudmuck 0:8f0d0ae0a077 873 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:8f0d0ae0a077 874 pcbuf[pcbuf_idx++] = c;
dudmuck 0:8f0d0ae0a077 875 pc.putc(c);
dudmuck 0:8f0d0ae0a077 876 }
dudmuck 0:8f0d0ae0a077 877 }
dudmuck 0:8f0d0ae0a077 878
dudmuck 10:00997daeb0c0 879 #ifdef SENSORS
dudmuck 10:00997daeb0c0 880 // Interrupt Handler
dudmuck 10:00997daeb0c0 881 void AirQualityInterrupt()
dudmuck 10:00997daeb0c0 882 {
dudmuck 10:00997daeb0c0 883 AnalogIn sensor(analogPin);
dudmuck 10:00997daeb0c0 884 airqualitysensor.last_vol = airqualitysensor.first_vol;
dudmuck 10:00997daeb0c0 885 airqualitysensor.first_vol = sensor.read()*1000;
dudmuck 10:00997daeb0c0 886 airqualitysensor.timer_index = 1;
dudmuck 10:00997daeb0c0 887 }
dudmuck 10:00997daeb0c0 888
dudmuck 10:00997daeb0c0 889 void button_isr()
dudmuck 10:00997daeb0c0 890 {
dudmuck 10:00997daeb0c0 891 button_cnt++;
dudmuck 10:00997daeb0c0 892 isr_printf("button_isr\r\n");
dudmuck 10:00997daeb0c0 893 if (!jumper_in.read()) {
dudmuck 10:00997daeb0c0 894 /* jumper not installed: manual uplink */
dudmuck 10:00997daeb0c0 895 send_uplink();
dudmuck 10:00997daeb0c0 896 }
dudmuck 10:00997daeb0c0 897 }
dudmuck 10:00997daeb0c0 898 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 899
dudmuck 10:00997daeb0c0 900
dudmuck 0:8f0d0ae0a077 901 /**
dudmuck 0:8f0d0ae0a077 902 * Main application entry point.
dudmuck 0:8f0d0ae0a077 903 */
dudmuck 0:8f0d0ae0a077 904 int main( void )
dudmuck 0:8f0d0ae0a077 905 {
dudmuck 0:8f0d0ae0a077 906 LoRaMacPrimitives_t LoRaMacPrimitives;
dudmuck 0:8f0d0ae0a077 907 LoRaMacCallback_t LoRaMacCallbacks;
dudmuck 0:8f0d0ae0a077 908 MibRequestConfirm_t mibReq;
dudmuck 0:8f0d0ae0a077 909
dudmuck 4:d9201410c87b 910 pc.baud(38400);
dudmuck 7:e238827f0e47 911 pc.attach(&rx_callback);
dudmuck 1:53c30224eda8 912 isr_printf("\r\nreset\r\n");
dudmuck 10:00997daeb0c0 913
dudmuck 10:00997daeb0c0 914 BoardInit( );
dudmuck 10:00997daeb0c0 915
dudmuck 0:8f0d0ae0a077 916 DeviceState = DEVICE_STATE_INIT;
dudmuck 10:00997daeb0c0 917
dudmuck 10:00997daeb0c0 918 #ifdef SENSORS
dudmuck 10:00997daeb0c0 919 airqualitysensor.init(analogPin, AirQualityInterrupt);
dudmuck 10:00997daeb0c0 920 if (button) {
dudmuck 10:00997daeb0c0 921 button.rise(&button_isr);
dudmuck 10:00997daeb0c0 922 printf("button-rise\r\n");
dudmuck 10:00997daeb0c0 923 } else {
dudmuck 10:00997daeb0c0 924 button.rise(&button_isr);
dudmuck 10:00997daeb0c0 925 printf("button-fall\r\n");
dudmuck 10:00997daeb0c0 926 }
dudmuck 10:00997daeb0c0 927 //water.mode(PullNone);
dudmuck 10:00997daeb0c0 928 water.mode(PullUp);
dudmuck 10:00997daeb0c0 929 #endif
dudmuck 10:00997daeb0c0 930
dudmuck 10:00997daeb0c0 931 jumper_out = 1;
dudmuck 10:00997daeb0c0 932 jumper_in.mode(PullDown);
dudmuck 0:8f0d0ae0a077 933
dudmuck 0:8f0d0ae0a077 934 while( 1 )
dudmuck 0:8f0d0ae0a077 935 {
dudmuck 0:8f0d0ae0a077 936 console();
dudmuck 0:8f0d0ae0a077 937
dudmuck 0:8f0d0ae0a077 938 switch( DeviceState )
dudmuck 0:8f0d0ae0a077 939 {
dudmuck 0:8f0d0ae0a077 940 case DEVICE_STATE_INIT:
dudmuck 0:8f0d0ae0a077 941 {
dudmuck 1:53c30224eda8 942 isr_printf("DEVICE_STATE_INIT\r\n");
dudmuck 0:8f0d0ae0a077 943 uplink_length = 2;
dudmuck 0:8f0d0ae0a077 944 LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
dudmuck 0:8f0d0ae0a077 945 LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
dudmuck 0:8f0d0ae0a077 946 LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
dudmuck 0:8f0d0ae0a077 947 LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
dudmuck 0:8f0d0ae0a077 948 LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
dudmuck 0:8f0d0ae0a077 949 if (LORAMAC_STATUS_OK != LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks )) {
dudmuck 1:53c30224eda8 950 isr_printf("LoRaMacInitialization() failed\r\n");
dudmuck 0:8f0d0ae0a077 951 for (;;) ;
dudmuck 0:8f0d0ae0a077 952 }
dudmuck 1:53c30224eda8 953 isr_printf("INIT-ok\r\n");
dudmuck 0:8f0d0ae0a077 954
dudmuck 0:8f0d0ae0a077 955 mibReq.Type = MIB_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 956 mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 957 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 958
dudmuck 0:8f0d0ae0a077 959 LoRaMacDownlinkStatus.DownlinkCounter = 0;
dudmuck 0:8f0d0ae0a077 960
dudmuck 0:8f0d0ae0a077 961 DeviceState = DEVICE_STATE_JOIN;
dudmuck 0:8f0d0ae0a077 962 break;
dudmuck 0:8f0d0ae0a077 963 }
dudmuck 0:8f0d0ae0a077 964 case DEVICE_STATE_JOIN:
dudmuck 0:8f0d0ae0a077 965 {
dudmuck 10:00997daeb0c0 966 if (jumper_in.read()) /* if jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 967 send_at_beacon = true;
dudmuck 0:8f0d0ae0a077 968 #if( OVER_THE_AIR_ACTIVATION != 0 )
dudmuck 0:8f0d0ae0a077 969 MlmeReq_t mlmeReq;
dudmuck 0:8f0d0ae0a077 970 // override software definition with hardware value
dudmuck 0:8f0d0ae0a077 971 BoardGetUniqueId(DevEui);
dudmuck 1:53c30224eda8 972 isr_printf("DevEUI ");
dudmuck 0:8f0d0ae0a077 973 for (int i = 0; i < 8; i++)
dudmuck 1:53c30224eda8 974 isr_printf("%02x ", DevEui[i]);
dudmuck 1:53c30224eda8 975 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 976
dudmuck 0:8f0d0ae0a077 977 mlmeReq.Type = MLME_JOIN;
dudmuck 0:8f0d0ae0a077 978
dudmuck 0:8f0d0ae0a077 979 mlmeReq.Req.Join.DevEui = DevEui;
dudmuck 0:8f0d0ae0a077 980 mlmeReq.Req.Join.AppEui = AppEui;
dudmuck 0:8f0d0ae0a077 981 mlmeReq.Req.Join.AppKey = AppKey;
dudmuck 0:8f0d0ae0a077 982 mlmeReq.Req.Join.NbTrials = 255;
dudmuck 0:8f0d0ae0a077 983
dudmuck 0:8f0d0ae0a077 984 if( NextTx == true )
dudmuck 0:8f0d0ae0a077 985 {
dudmuck 0:8f0d0ae0a077 986 LoRaMacMlmeRequest( &mlmeReq );
dudmuck 0:8f0d0ae0a077 987 }
dudmuck 0:8f0d0ae0a077 988 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 989 #else
dudmuck 0:8f0d0ae0a077 990 mibReq.Type = MIB_NET_ID;
dudmuck 0:8f0d0ae0a077 991 mibReq.Param.NetID = LORAWAN_NETWORK_ID;
dudmuck 0:8f0d0ae0a077 992 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 993
dudmuck 0:8f0d0ae0a077 994 mibReq.Type = MIB_DEV_ADDR;
dudmuck 0:8f0d0ae0a077 995 mibReq.Param.DevAddr = DevAddr;
dudmuck 0:8f0d0ae0a077 996 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 997
dudmuck 0:8f0d0ae0a077 998 mibReq.Type = MIB_NWK_SKEY;
dudmuck 0:8f0d0ae0a077 999 mibReq.Param.NwkSKey = NwkSKey;
dudmuck 0:8f0d0ae0a077 1000 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1001
dudmuck 0:8f0d0ae0a077 1002 mibReq.Type = MIB_APP_SKEY;
dudmuck 0:8f0d0ae0a077 1003 mibReq.Param.AppSKey = AppSKey;
dudmuck 0:8f0d0ae0a077 1004 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1005
dudmuck 0:8f0d0ae0a077 1006 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 0:8f0d0ae0a077 1007 mibReq.Param.IsNetworkJoined = true;
dudmuck 0:8f0d0ae0a077 1008 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1009
dudmuck 0:8f0d0ae0a077 1010 DeviceState = DEVICE_STATE_SEND;
dudmuck 0:8f0d0ae0a077 1011 #endif
dudmuck 0:8f0d0ae0a077 1012 break;
dudmuck 0:8f0d0ae0a077 1013 }
dudmuck 0:8f0d0ae0a077 1014 case DEVICE_STATE_SEND:
dudmuck 0:8f0d0ae0a077 1015 {
dudmuck 0:8f0d0ae0a077 1016 if( NextTx == true )
dudmuck 0:8f0d0ae0a077 1017 {
dudmuck 0:8f0d0ae0a077 1018 PrepareTxFrame( AppPort );
dudmuck 0:8f0d0ae0a077 1019
dudmuck 0:8f0d0ae0a077 1020 NextTx = SendFrame( );
dudmuck 0:8f0d0ae0a077 1021 }
dudmuck 2:f2d9aa163652 1022
dudmuck 0:8f0d0ae0a077 1023 // Schedule next packet transmission
dudmuck 0:8f0d0ae0a077 1024 TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
dudmuck 2:f2d9aa163652 1025 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1026 break;
dudmuck 0:8f0d0ae0a077 1027 }
dudmuck 0:8f0d0ae0a077 1028 case DEVICE_STATE_CYCLE:
dudmuck 0:8f0d0ae0a077 1029 {
dudmuck 0:8f0d0ae0a077 1030 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1031
dudmuck 0:8f0d0ae0a077 1032 // Schedule next packet transmission
dudmuck 0:8f0d0ae0a077 1033 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, TxDutyCycleTime * 1000);
dudmuck 0:8f0d0ae0a077 1034 break;
dudmuck 0:8f0d0ae0a077 1035 }
dudmuck 0:8f0d0ae0a077 1036 case DEVICE_STATE_SLEEP:
dudmuck 0:8f0d0ae0a077 1037 {
dudmuck 1:53c30224eda8 1038 //isr_printf("sleep %u\r\n", queue.tick());
dudmuck 0:8f0d0ae0a077 1039 // Wake up through events
dudmuck 0:8f0d0ae0a077 1040 break;
dudmuck 0:8f0d0ae0a077 1041 }
dudmuck 0:8f0d0ae0a077 1042 default:
dudmuck 0:8f0d0ae0a077 1043 {
dudmuck 0:8f0d0ae0a077 1044 DeviceState = DEVICE_STATE_INIT;
dudmuck 0:8f0d0ae0a077 1045 break;
dudmuck 0:8f0d0ae0a077 1046 }
dudmuck 0:8f0d0ae0a077 1047 }
dudmuck 1:53c30224eda8 1048
dudmuck 1:53c30224eda8 1049 bottom_half();
dudmuck 1:53c30224eda8 1050
dudmuck 1:53c30224eda8 1051 } // ..while( 1 )
dudmuck 0:8f0d0ae0a077 1052 }