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:
Mon Aug 14 11:30:36 2017 -0700
Revision:
27:c8b432b2a4a8
Parent:
26:8227a4edb216
Child:
28:36be305a5e5e
add sequency number to sensor polling

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 11:4c337f5bbe4c 21 #include "commands.h"
dudmuck 0:8f0d0ae0a077 22
dudmuck 23:a862b5601663 23 #ifdef ENABLE_LUMINOSITY
dudmuck 12:ed33c53afcaf 24 #include "TSL2561.h"
dudmuck 12:ed33c53afcaf 25 //TSL2561 tsl2561(TSL2561_ADDR_FLOAT); // https://developer.mbed.org/components/Grove-Digital-Light-Sensor/
dudmuck 12:ed33c53afcaf 26 TSL2561 tsl2561(TSL2561_ADDR_LOW);
dudmuck 23:a862b5601663 27 #endif
dudmuck 23:a862b5601663 28
dudmuck 23:a862b5601663 29 #ifdef ENABLE_RGB
dudmuck 23:a862b5601663 30 #include "ChainableLED.h"
dudmuck 23:a862b5601663 31 ChainableLED rgb(D6, D7, 1); // https://developer.mbed.org/components/Grove-Chainable-RGB-LED/
dudmuck 10:00997daeb0c0 32 #endif
dudmuck 10:00997daeb0c0 33
dudmuck 25:fed9d5b77183 34 #ifdef TYPE_ABZ
dudmuck 25:fed9d5b77183 35 InterruptIn user_button(PB_2);
dudmuck 25:fed9d5b77183 36 #else
dudmuck 25:fed9d5b77183 37 InterruptIn user_button(USER_BUTTON);
dudmuck 25:fed9d5b77183 38 #endif
dudmuck 25:fed9d5b77183 39
dudmuck 23:a862b5601663 40 #ifdef SENSORS
dudmuck 23:a862b5601663 41 #ifdef TYPE_ABZ /* DISCO_L072CZ_LRWAN1 */
dudmuck 23:a862b5601663 42 PwmOut pwm(PB_5);
dudmuck 23:a862b5601663 43 DigitalIn pc8_in(PB_13);
dudmuck 23:a862b5601663 44 DigitalOut pc6_out(PB_14);
dudmuck 23:a862b5601663 45 AnalogIn a0(PA_0);
dudmuck 23:a862b5601663 46 AnalogIn a2(PA_4);
dudmuck 23:a862b5601663 47 #else
dudmuck 23:a862b5601663 48 PwmOut pwm(PB_11);
dudmuck 23:a862b5601663 49 DigitalIn pc8_in(PC_8);
dudmuck 23:a862b5601663 50 DigitalOut pc6_out(PC_6);
dudmuck 23:a862b5601663 51 AnalogIn a1(A1); // https://developer.mbed.org/teams/Seeed/wiki/Potentiometer
dudmuck 23:a862b5601663 52 AnalogIn a3(A3); // https://developer.mbed.org/teams/Seeed/wiki/Potentiometer
dudmuck 23:a862b5601663 53 #endif
dudmuck 26:8227a4edb216 54
dudmuck 26:8227a4edb216 55 #define N_SAMPLES 4
dudmuck 26:8227a4edb216 56 struct sens {
dudmuck 27:c8b432b2a4a8 57 uint16_t seq;
dudmuck 26:8227a4edb216 58 uint16_t ain_A, ain_B;
dudmuck 26:8227a4edb216 59 uint8_t pins;
dudmuck 26:8227a4edb216 60 } sensor[N_SAMPLES];
dudmuck 26:8227a4edb216 61 uint8_t sensor_in_idx, sensor_out_idx;
dudmuck 27:c8b432b2a4a8 62 uint16_t sample_seqnum;
dudmuck 26:8227a4edb216 63
dudmuck 26:8227a4edb216 64 void sensor_poll()
dudmuck 26:8227a4edb216 65 {
dudmuck 27:c8b432b2a4a8 66 sensor[sensor_in_idx].seq = sample_seqnum++;
dudmuck 26:8227a4edb216 67 #ifdef TYPE_ABZ
dudmuck 26:8227a4edb216 68 sensor[sensor_in_idx].ain_A = a0.read_u16();
dudmuck 26:8227a4edb216 69 sensor[sensor_in_idx].ain_B = a2.read_u16();
dudmuck 26:8227a4edb216 70 #else
dudmuck 26:8227a4edb216 71 sensor[sensor_in_idx].ain_A = a1.read_u16();
dudmuck 26:8227a4edb216 72 sensor[sensor_in_idx].ain_B = a3.read_u16();
dudmuck 26:8227a4edb216 73 #endif
dudmuck 26:8227a4edb216 74 sensor[sensor_in_idx].pins = pc8_in.read();
dudmuck 26:8227a4edb216 75 sensor[sensor_in_idx].pins <<= 1;
dudmuck 26:8227a4edb216 76 sensor[sensor_in_idx].pins = pc6_out.read();
dudmuck 26:8227a4edb216 77 if (++sensor_in_idx == N_SAMPLES)
dudmuck 26:8227a4edb216 78 sensor_in_idx = 0;
dudmuck 26:8227a4edb216 79 }
dudmuck 26:8227a4edb216 80 LowPowerTicker sensor_ticker;
dudmuck 23:a862b5601663 81 #endif /* SENSORS */
dudmuck 23:a862b5601663 82
dudmuck 20:42839629a5dc 83 DigitalOut pc2(PC_2);
dudmuck 12:ed33c53afcaf 84
dudmuck 23:a862b5601663 85 #if defined(TARGET_DISCO_L072CZ_LRWAN1) || ( defined(TARGET_NUCLEO_L073RZ) && defined(TYPE_ABZ) )
dudmuck 23:a862b5601663 86 DigitalOut jumper_out(PA_11);
dudmuck 23:a862b5601663 87 InterruptIn jumper_in(PA_12);
dudmuck 23:a862b5601663 88 #else
dudmuck 23:a862b5601663 89 DigitalOut jumper_out(PC_10);
dudmuck 23:a862b5601663 90 InterruptIn jumper_in(PC_12);
dudmuck 23:a862b5601663 91 #endif /* murata */
dudmuck 10:00997daeb0c0 92
dudmuck 0:8f0d0ae0a077 93 char pcbuf[128];
dudmuck 0:8f0d0ae0a077 94 int pcbuf_len;
dudmuck 0:8f0d0ae0a077 95
dudmuck 0:8f0d0ae0a077 96 /*!
dudmuck 0:8f0d0ae0a077 97 * Defines the application data transmission duty cycle. 5s, value in [ms].
dudmuck 0:8f0d0ae0a077 98 */
dudmuck 0:8f0d0ae0a077 99 #define APP_TX_DUTYCYCLE 5000
dudmuck 0:8f0d0ae0a077 100
dudmuck 0:8f0d0ae0a077 101 /*!
dudmuck 0:8f0d0ae0a077 102 * Defines a random delay for application data transmission duty cycle. 1s,
dudmuck 0:8f0d0ae0a077 103 * value in [ms].
dudmuck 0:8f0d0ae0a077 104 */
dudmuck 0:8f0d0ae0a077 105 #define APP_TX_DUTYCYCLE_RND 1000
dudmuck 0:8f0d0ae0a077 106
dudmuck 0:8f0d0ae0a077 107 /*!
dudmuck 0:8f0d0ae0a077 108 * Default datarate
dudmuck 0:8f0d0ae0a077 109 */
dudmuck 0:8f0d0ae0a077 110 #define LORAWAN_DEFAULT_DATARATE DR_10
dudmuck 0:8f0d0ae0a077 111
dudmuck 0:8f0d0ae0a077 112 /*!
dudmuck 0:8f0d0ae0a077 113 * LoRaWAN confirmed messages
dudmuck 0:8f0d0ae0a077 114 */
dudmuck 0:8f0d0ae0a077 115 #define LORAWAN_CONFIRMED_MSG_ON true
dudmuck 0:8f0d0ae0a077 116
dudmuck 0:8f0d0ae0a077 117 /*!
dudmuck 0:8f0d0ae0a077 118 * LoRaWAN application port
dudmuck 0:8f0d0ae0a077 119 */
dudmuck 0:8f0d0ae0a077 120 #define LORAWAN_APP_PORT 15
dudmuck 0:8f0d0ae0a077 121
dudmuck 0:8f0d0ae0a077 122 /*!
dudmuck 0:8f0d0ae0a077 123 * User application data buffer size
dudmuck 0:8f0d0ae0a077 124 */
dudmuck 0:8f0d0ae0a077 125 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
dudmuck 0:8f0d0ae0a077 126 #define LORAWAN_APP_DATA_SIZE 6
dudmuck 0:8f0d0ae0a077 127
dudmuck 0:8f0d0ae0a077 128 #else
dudmuck 0:8f0d0ae0a077 129 #define LORAWAN_APP_DATA_SIZE 1
dudmuck 0:8f0d0ae0a077 130
dudmuck 0:8f0d0ae0a077 131 #endif
dudmuck 0:8f0d0ae0a077 132
dudmuck 0:8f0d0ae0a077 133 static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
dudmuck 0:8f0d0ae0a077 134 static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
dudmuck 0:8f0d0ae0a077 135 static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
dudmuck 0:8f0d0ae0a077 136
dudmuck 0:8f0d0ae0a077 137 #if( OVER_THE_AIR_ACTIVATION == 0 )
dudmuck 0:8f0d0ae0a077 138
dudmuck 0:8f0d0ae0a077 139 static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
dudmuck 0:8f0d0ae0a077 140 static uint8_t AppSKey[] = LORAWAN_APPSKEY;
dudmuck 0:8f0d0ae0a077 141
dudmuck 0:8f0d0ae0a077 142 /*!
dudmuck 0:8f0d0ae0a077 143 * Device address
dudmuck 0:8f0d0ae0a077 144 */
dudmuck 0:8f0d0ae0a077 145 static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
dudmuck 0:8f0d0ae0a077 146
dudmuck 0:8f0d0ae0a077 147 #endif
dudmuck 0:8f0d0ae0a077 148
dudmuck 0:8f0d0ae0a077 149 /*!
dudmuck 0:8f0d0ae0a077 150 * Application port
dudmuck 0:8f0d0ae0a077 151 */
dudmuck 23:a862b5601663 152 #if defined(SENSORS)
dudmuck 10:00997daeb0c0 153 static uint8_t AppPort = SENSOR_PORT;
dudmuck 10:00997daeb0c0 154 #else
dudmuck 10:00997daeb0c0 155 static uint8_t AppPort = LORAWAN_APP_PORT;
dudmuck 10:00997daeb0c0 156 #endif
dudmuck 0:8f0d0ae0a077 157
dudmuck 0:8f0d0ae0a077 158 /*!
dudmuck 0:8f0d0ae0a077 159 * User application data size
dudmuck 0:8f0d0ae0a077 160 */
dudmuck 0:8f0d0ae0a077 161 static uint8_t AppDataSize = LORAWAN_APP_DATA_SIZE;
dudmuck 0:8f0d0ae0a077 162 static unsigned int uplink_length; // user assigned
dudmuck 0:8f0d0ae0a077 163
dudmuck 0:8f0d0ae0a077 164 /*!
dudmuck 0:8f0d0ae0a077 165 * User application data buffer size
dudmuck 0:8f0d0ae0a077 166 */
dudmuck 0:8f0d0ae0a077 167 #define LORAWAN_APP_DATA_MAX_SIZE 128
dudmuck 0:8f0d0ae0a077 168
dudmuck 0:8f0d0ae0a077 169 /*!
dudmuck 0:8f0d0ae0a077 170 * User application data
dudmuck 0:8f0d0ae0a077 171 */
dudmuck 0:8f0d0ae0a077 172 static uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE];
dudmuck 0:8f0d0ae0a077 173
dudmuck 0:8f0d0ae0a077 174 /*!
dudmuck 0:8f0d0ae0a077 175 * Indicates if the node is sending confirmed or unconfirmed messages
dudmuck 0:8f0d0ae0a077 176 */
dudmuck 0:8f0d0ae0a077 177 static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
dudmuck 0:8f0d0ae0a077 178
dudmuck 0:8f0d0ae0a077 179 /*!
dudmuck 0:8f0d0ae0a077 180 * Defines the application data transmission duty cycle
dudmuck 0:8f0d0ae0a077 181 */
dudmuck 0:8f0d0ae0a077 182 static uint32_t TxDutyCycleTime;
dudmuck 0:8f0d0ae0a077 183
dudmuck 0:8f0d0ae0a077 184 /*!
dudmuck 0:8f0d0ae0a077 185 * Timer to handle the application data transmission duty cycle
dudmuck 0:8f0d0ae0a077 186 */
dudmuck 17:3215f12051f9 187 LowPowerTimeout TxNextPacketTimeout;
dudmuck 0:8f0d0ae0a077 188
dudmuck 0:8f0d0ae0a077 189 volatile bool send_at_beacon;
dudmuck 0:8f0d0ae0a077 190 volatile bool awaiting_mcps_indic;
dudmuck 21:500ff43d8424 191 bool join_retry;
dudmuck 0:8f0d0ae0a077 192 /*!
dudmuck 0:8f0d0ae0a077 193 * Specifies the state of the application LED
dudmuck 0:8f0d0ae0a077 194 */
dudmuck 0:8f0d0ae0a077 195 static bool AppLedStateOn = false;
dudmuck 0:8f0d0ae0a077 196
dudmuck 0:8f0d0ae0a077 197 /*!
dudmuck 0:8f0d0ae0a077 198 * Device states
dudmuck 0:8f0d0ae0a077 199 */
dudmuck 0:8f0d0ae0a077 200 static enum eDeviceState
dudmuck 0:8f0d0ae0a077 201 {
dudmuck 0:8f0d0ae0a077 202 DEVICE_STATE_INIT,
dudmuck 0:8f0d0ae0a077 203 DEVICE_STATE_JOIN,
dudmuck 0:8f0d0ae0a077 204 DEVICE_STATE_CYCLE,
dudmuck 16:915815632c1f 205 DEVICE_STATE_SLEEP,
dudmuck 18:9ac71c0eb70d 206 DEVICE_STATE_REJOIN,
dudmuck 18:9ac71c0eb70d 207 DEVICE_STATE_UPLINK
dudmuck 0:8f0d0ae0a077 208 }DeviceState;
dudmuck 0:8f0d0ae0a077 209
dudmuck 0:8f0d0ae0a077 210 /*!
dudmuck 0:8f0d0ae0a077 211 * Strucure containing the Uplink status
dudmuck 0:8f0d0ae0a077 212 */
dudmuck 0:8f0d0ae0a077 213 struct sLoRaMacUplinkStatus
dudmuck 0:8f0d0ae0a077 214 {
dudmuck 0:8f0d0ae0a077 215 uint8_t Acked;
dudmuck 0:8f0d0ae0a077 216 //int8_t Datarate;
dudmuck 0:8f0d0ae0a077 217 uint16_t UplinkCounter;
dudmuck 0:8f0d0ae0a077 218 uint8_t Port;
dudmuck 0:8f0d0ae0a077 219 uint8_t *Buffer;
dudmuck 0:8f0d0ae0a077 220 uint8_t BufferSize;
dudmuck 0:8f0d0ae0a077 221 }LoRaMacUplinkStatus;
dudmuck 0:8f0d0ae0a077 222 //volatile bool UplinkStatusUpdated = false;
dudmuck 0:8f0d0ae0a077 223
dudmuck 0:8f0d0ae0a077 224 /*!
dudmuck 0:8f0d0ae0a077 225 * Strucure containing the Downlink status
dudmuck 0:8f0d0ae0a077 226 */
dudmuck 0:8f0d0ae0a077 227 struct sLoRaMacDownlinkStatus
dudmuck 0:8f0d0ae0a077 228 {
dudmuck 0:8f0d0ae0a077 229 int16_t Rssi;
dudmuck 0:8f0d0ae0a077 230 int8_t Snr;
dudmuck 0:8f0d0ae0a077 231 uint16_t DownlinkCounter;
dudmuck 0:8f0d0ae0a077 232 bool RxData;
dudmuck 0:8f0d0ae0a077 233 uint8_t Port;
dudmuck 0:8f0d0ae0a077 234 uint8_t *Buffer;
dudmuck 0:8f0d0ae0a077 235 uint8_t BufferSize;
dudmuck 0:8f0d0ae0a077 236 }LoRaMacDownlinkStatus;
dudmuck 0:8f0d0ae0a077 237
dudmuck 2:f2d9aa163652 238 static uint8_t missed_count;
dudmuck 2:f2d9aa163652 239
dudmuck 0:8f0d0ae0a077 240
dudmuck 0:8f0d0ae0a077 241 /*!
dudmuck 0:8f0d0ae0a077 242 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 243 */
dudmuck 0:8f0d0ae0a077 244 static void PrepareTxFrame( uint8_t port )
dudmuck 0:8f0d0ae0a077 245 {
dudmuck 0:8f0d0ae0a077 246 switch( port )
dudmuck 0:8f0d0ae0a077 247 {
dudmuck 0:8f0d0ae0a077 248 case 15:
dudmuck 0:8f0d0ae0a077 249 {
dudmuck 0:8f0d0ae0a077 250 AppData[0] = AppLedStateOn;
dudmuck 0:8f0d0ae0a077 251 if( IsTxConfirmed == true )
dudmuck 0:8f0d0ae0a077 252 {
dudmuck 0:8f0d0ae0a077 253 AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
dudmuck 0:8f0d0ae0a077 254 AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter;
dudmuck 0:8f0d0ae0a077 255 AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8;
dudmuck 0:8f0d0ae0a077 256 AppData[4] = LoRaMacDownlinkStatus.Rssi;
dudmuck 0:8f0d0ae0a077 257 AppData[5] = LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 258 }
dudmuck 0:8f0d0ae0a077 259 }
dudmuck 0:8f0d0ae0a077 260 break;
dudmuck 23:a862b5601663 261 #if defined(SENSORS)
dudmuck 10:00997daeb0c0 262 case SENSOR_PORT:
dudmuck 12:ed33c53afcaf 263 {
dudmuck 26:8227a4edb216 264 uint16_t x = 0xffff;
dudmuck 23:a862b5601663 265 #ifdef ENABLE_LUMINOSITY
dudmuck 23:a862b5601663 266 x = tsl2561.getLuminosity(TSL2561_VISIBLE);
dudmuck 23:a862b5601663 267 #endif
dudmuck 26:8227a4edb216 268 AppDataSize = 0;
dudmuck 26:8227a4edb216 269 AppData[AppDataSize++] = x >> 8;
dudmuck 26:8227a4edb216 270 AppData[AppDataSize++] = x & 0xff;
dudmuck 26:8227a4edb216 271 while (sensor_in_idx != sensor_out_idx) {
dudmuck 27:c8b432b2a4a8 272 AppData[AppDataSize++] = sensor[sensor_out_idx].seq >> 8;
dudmuck 27:c8b432b2a4a8 273 AppData[AppDataSize++] = sensor[sensor_out_idx].seq & 0xff;
dudmuck 26:8227a4edb216 274 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_A >> 8;
dudmuck 26:8227a4edb216 275 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_A & 0xff;
dudmuck 26:8227a4edb216 276 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_B >> 8;
dudmuck 26:8227a4edb216 277 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_B & 0xff;
dudmuck 26:8227a4edb216 278 AppData[AppDataSize++] = sensor[sensor_out_idx].pins;
dudmuck 26:8227a4edb216 279 if (++sensor_out_idx == N_SAMPLES)
dudmuck 26:8227a4edb216 280 sensor_out_idx = 0;
dudmuck 26:8227a4edb216 281 }
dudmuck 12:ed33c53afcaf 282 }
dudmuck 10:00997daeb0c0 283 break;
dudmuck 23:a862b5601663 284 #endif /* SENSORS */
dudmuck 0:8f0d0ae0a077 285 default:
dudmuck 0:8f0d0ae0a077 286 break;
dudmuck 0:8f0d0ae0a077 287 }
dudmuck 0:8f0d0ae0a077 288 }
dudmuck 0:8f0d0ae0a077 289
dudmuck 0:8f0d0ae0a077 290 void
dudmuck 0:8f0d0ae0a077 291 LoRaMacEventInfoStatus_to_string(LoRaMacEventInfoStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 292 {
dudmuck 0:8f0d0ae0a077 293 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 294
dudmuck 0:8f0d0ae0a077 295 switch (status) {
dudmuck 0:8f0d0ae0a077 296 case LORAMAC_EVENT_INFO_STATUS_RX_ERROR: ptr = "RX_ERROR"; break;
dudmuck 0:8f0d0ae0a077 297 case LORAMAC_EVENT_INFO_STATUS_OK: ptr = "OK"; break;
dudmuck 2:f2d9aa163652 298 case LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE: ptr = "ERROR_RX_MTYPE"; break;
dudmuck 2:f2d9aa163652 299 case LORAMAC_EVENT_INFO_STATUS_ERROR_SEND: ptr = "ERROR_SEND"; break;
dudmuck 2:f2d9aa163652 300 case LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT: ptr = "ERROR_JOIN_ACCEPT"; break;
dudmuck 2:f2d9aa163652 301 case LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ: ptr = "ERROR_MLMEREQ"; break;
dudmuck 2:f2d9aa163652 302 case LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ: ptr = "ERROR_MCPSREQ"; break;
dudmuck 2:f2d9aa163652 303 //case LORAMAC_EVENT_INFO_STATUS_ERROR: ptr = "ERROR"; break;
dudmuck 2:f2d9aa163652 304
dudmuck 0:8f0d0ae0a077 305 case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: ptr = "TX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 306 case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT: ptr = "RX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 307 case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL: ptr = "JOIN_FAIL"; break;
dudmuck 0:8f0d0ae0a077 308 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED: ptr = "DOWNLINK_REPEATED"; break;
dudmuck 0:8f0d0ae0a077 309 case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: ptr = "TX_DR_PAYLOAD_SIZE_ERROR"; break;
dudmuck 0:8f0d0ae0a077 310 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS: ptr = "DOWNLINK_TOO_MANY_FRAMES_LOSS"; break;
dudmuck 0:8f0d0ae0a077 311 case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL: ptr = "ADDRESS_FAIL"; break;
dudmuck 0:8f0d0ae0a077 312 case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL: ptr = "MIC_FAIL"; break;
dudmuck 0:8f0d0ae0a077 313 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED: ptr = "BEACON_LOCKED"; break;
dudmuck 0:8f0d0ae0a077 314 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOST: ptr = "BEACON_LOST"; break;
dudmuck 0:8f0d0ae0a077 315 case LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND: ptr = "BEACON_NOT_FOUND"; break;
dudmuck 16:915815632c1f 316 case LORAMAC_EVENT_INFO_STATUS_STOP: ptr = "STOP"; break;
dudmuck 0:8f0d0ae0a077 317 }
dudmuck 0:8f0d0ae0a077 318
dudmuck 0:8f0d0ae0a077 319 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 320 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 321 }
dudmuck 0:8f0d0ae0a077 322
dudmuck 0:8f0d0ae0a077 323 void
dudmuck 0:8f0d0ae0a077 324 LoRaMacStatus_to_string(LoRaMacStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 325 {
dudmuck 0:8f0d0ae0a077 326 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 327
dudmuck 0:8f0d0ae0a077 328 switch (status) {
dudmuck 0:8f0d0ae0a077 329 case LORAMAC_STATUS_OK: ptr = "OK"; break;
dudmuck 0:8f0d0ae0a077 330 case LORAMAC_STATUS_BUSY: ptr = "BUSY"; break;
dudmuck 0:8f0d0ae0a077 331 case LORAMAC_STATUS_SERVICE_UNKNOWN: ptr = "SERVICE_UNKNOWN"; break;
dudmuck 0:8f0d0ae0a077 332 case LORAMAC_STATUS_PARAMETER_INVALID: ptr = "PARAMETER_INVALID"; break;
dudmuck 0:8f0d0ae0a077 333 case LORAMAC_STATUS_FREQUENCY_INVALID: ptr = "FREQUENCY_INVALID"; break;
dudmuck 0:8f0d0ae0a077 334 case LORAMAC_STATUS_DATARATE_INVALID: ptr = "DATARATE_INVALID"; break;
dudmuck 0:8f0d0ae0a077 335 case LORAMAC_STATUS_FREQ_AND_DR_INVALID: ptr = "FREQ_AND_DR_INVALID"; break;
dudmuck 0:8f0d0ae0a077 336 case LORAMAC_STATUS_NO_NETWORK_JOINED: ptr = "NO_NETWORK_JOINED"; break;
dudmuck 0:8f0d0ae0a077 337 case LORAMAC_STATUS_LENGTH_ERROR: ptr = "LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 338 case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR: ptr = "MAC_CMD_LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 339 case LORAMAC_STATUS_DEVICE_OFF: ptr = "DEVICE_OFF"; break;
dudmuck 0:8f0d0ae0a077 340 }
dudmuck 0:8f0d0ae0a077 341 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 342 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 343 }
dudmuck 0:8f0d0ae0a077 344
dudmuck 17:3215f12051f9 345 static void OnTxNextPacketTimerEvent( void );
dudmuck 5:c108560af4c3 346
dudmuck 5:c108560af4c3 347 /*!
dudmuck 0:8f0d0ae0a077 348 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 349 *
dudmuck 0:8f0d0ae0a077 350 * \retval [0: frame could be send, 1: error]
dudmuck 0:8f0d0ae0a077 351 */
dudmuck 17:3215f12051f9 352 static bool SendFrame(uint8_t port)
dudmuck 0:8f0d0ae0a077 353 {
dudmuck 0:8f0d0ae0a077 354 McpsReq_t mcpsReq;
dudmuck 0:8f0d0ae0a077 355 LoRaMacTxInfo_t txInfo;
dudmuck 0:8f0d0ae0a077 356 LoRaMacStatus_t status;
dudmuck 0:8f0d0ae0a077 357 char str[64];
dudmuck 0:8f0d0ae0a077 358
dudmuck 0:8f0d0ae0a077 359 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 360 {
dudmuck 0:8f0d0ae0a077 361 // Send empty frame in order to flush MAC commands
dudmuck 0:8f0d0ae0a077 362 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 363 mcpsReq.Req.Unconfirmed.fBuffer = NULL;
dudmuck 0:8f0d0ae0a077 364 mcpsReq.Req.Unconfirmed.fBufferSize = 0;
dudmuck 0:8f0d0ae0a077 365
dudmuck 0:8f0d0ae0a077 366 LoRaMacUplinkStatus.Acked = false;
dudmuck 0:8f0d0ae0a077 367 LoRaMacUplinkStatus.Port = 0;
dudmuck 0:8f0d0ae0a077 368 LoRaMacUplinkStatus.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 369 LoRaMacUplinkStatus.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 370 }
dudmuck 0:8f0d0ae0a077 371 else
dudmuck 0:8f0d0ae0a077 372 {
dudmuck 0:8f0d0ae0a077 373 LoRaMacUplinkStatus.Acked = false;
dudmuck 12:ed33c53afcaf 374 LoRaMacUplinkStatus.Port = port;
dudmuck 0:8f0d0ae0a077 375 LoRaMacUplinkStatus.Buffer = AppData;
dudmuck 0:8f0d0ae0a077 376 LoRaMacUplinkStatus.BufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 377
dudmuck 0:8f0d0ae0a077 378 if( IsTxConfirmed == false )
dudmuck 0:8f0d0ae0a077 379 {
dudmuck 0:8f0d0ae0a077 380 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 12:ed33c53afcaf 381 mcpsReq.Req.Unconfirmed.fPort = port;
dudmuck 0:8f0d0ae0a077 382 mcpsReq.Req.Unconfirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 383 mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 384 //mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 385 }
dudmuck 0:8f0d0ae0a077 386 else
dudmuck 0:8f0d0ae0a077 387 {
dudmuck 0:8f0d0ae0a077 388 mcpsReq.Type = MCPS_CONFIRMED;
dudmuck 12:ed33c53afcaf 389 mcpsReq.Req.Confirmed.fPort = port;
dudmuck 0:8f0d0ae0a077 390 mcpsReq.Req.Confirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 391 mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 392 mcpsReq.Req.Confirmed.NbTrials = 8;
dudmuck 0:8f0d0ae0a077 393 //mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 394 }
dudmuck 0:8f0d0ae0a077 395 }
dudmuck 0:8f0d0ae0a077 396
dudmuck 0:8f0d0ae0a077 397 status = LoRaMacMcpsRequest( &mcpsReq );
dudmuck 0:8f0d0ae0a077 398 if( status == LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 399 {
dudmuck 0:8f0d0ae0a077 400 awaiting_mcps_indic = true;
dudmuck 0:8f0d0ae0a077 401 return false;
dudmuck 0:8f0d0ae0a077 402 }
dudmuck 0:8f0d0ae0a077 403 LoRaMacStatus_to_string(status, str);
dudmuck 1:53c30224eda8 404 isr_printf("send failed:%s\r\n", str);
dudmuck 16:915815632c1f 405
dudmuck 21:500ff43d8424 406 if (status == LORAMAC_STATUS_NO_NETWORK_JOINED) {
dudmuck 21:500ff43d8424 407 join_retry = true;
dudmuck 26:8227a4edb216 408 #ifdef SENSORS
dudmuck 26:8227a4edb216 409 sensor_ticker.detach();
dudmuck 26:8227a4edb216 410 #endif
dudmuck 21:500ff43d8424 411 } else {
dudmuck 17:3215f12051f9 412 AppPort = port;
dudmuck 17:3215f12051f9 413 TxNextPacketTimeout.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 22:999a7e7698a8 414 if (status == LORAMAC_STATUS_BUSY)
dudmuck 22:999a7e7698a8 415 send_at_beacon = true;
dudmuck 17:3215f12051f9 416 }
dudmuck 16:915815632c1f 417
dudmuck 0:8f0d0ae0a077 418 return true;
dudmuck 0:8f0d0ae0a077 419 }
dudmuck 0:8f0d0ae0a077 420
dudmuck 17:3215f12051f9 421 /*!
dudmuck 17:3215f12051f9 422 * \brief Function executed on TxNextPacket Timeout event
dudmuck 17:3215f12051f9 423 */
dudmuck 17:3215f12051f9 424 static void OnTxNextPacketTimerEvent( void )
dudmuck 17:3215f12051f9 425 {
dudmuck 17:3215f12051f9 426 MibRequestConfirm_t mibReq;
dudmuck 17:3215f12051f9 427 LoRaMacStatus_t status;
dudmuck 17:3215f12051f9 428
dudmuck 17:3215f12051f9 429 if (DeviceState == DEVICE_STATE_REJOIN) {
dudmuck 17:3215f12051f9 430 isr_printf("unjoin\r\n");
dudmuck 17:3215f12051f9 431 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 17:3215f12051f9 432 mibReq.Param.IsNetworkJoined = false;
dudmuck 26:8227a4edb216 433 #ifdef SENSORS
dudmuck 26:8227a4edb216 434 sensor_ticker.detach();
dudmuck 26:8227a4edb216 435 #endif
dudmuck 17:3215f12051f9 436 if (LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK) {
dudmuck 17:3215f12051f9 437 TxNextPacketTimeout.attach_us(&OnTxNextPacketTimerEvent, 500000);
dudmuck 17:3215f12051f9 438 return;
dudmuck 17:3215f12051f9 439 }
dudmuck 17:3215f12051f9 440 }
dudmuck 17:3215f12051f9 441
dudmuck 17:3215f12051f9 442 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 17:3215f12051f9 443 status = LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 17:3215f12051f9 444
dudmuck 17:3215f12051f9 445 isr_printf("OnTxNextPacketTimerEvent() ");
dudmuck 17:3215f12051f9 446 if( status == LORAMAC_STATUS_OK )
dudmuck 17:3215f12051f9 447 {
dudmuck 17:3215f12051f9 448 if( mibReq.Param.IsNetworkJoined == true )
dudmuck 17:3215f12051f9 449 {
dudmuck 17:3215f12051f9 450 isr_printf("send");
dudmuck 18:9ac71c0eb70d 451 DeviceState = DEVICE_STATE_UPLINK;
dudmuck 17:3215f12051f9 452 }
dudmuck 17:3215f12051f9 453 else
dudmuck 17:3215f12051f9 454 {
dudmuck 17:3215f12051f9 455 isr_printf("join");
dudmuck 17:3215f12051f9 456 DeviceState = DEVICE_STATE_JOIN;
dudmuck 17:3215f12051f9 457 }
dudmuck 17:3215f12051f9 458 }
dudmuck 17:3215f12051f9 459 isr_printf("\r\n");
dudmuck 17:3215f12051f9 460 }
dudmuck 17:3215f12051f9 461
dudmuck 0:8f0d0ae0a077 462 void
dudmuck 0:8f0d0ae0a077 463 send_uplink()
dudmuck 0:8f0d0ae0a077 464 {
dudmuck 0:8f0d0ae0a077 465 AppDataSize = uplink_length;
dudmuck 18:9ac71c0eb70d 466 DeviceState = DEVICE_STATE_UPLINK;
dudmuck 0:8f0d0ae0a077 467 }
dudmuck 0:8f0d0ae0a077 468
dudmuck 0:8f0d0ae0a077 469 /*!
dudmuck 0:8f0d0ae0a077 470 * \brief MCPS-Confirm event function
dudmuck 0:8f0d0ae0a077 471 *
dudmuck 0:8f0d0ae0a077 472 * \param [IN] mcpsConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 473 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 474 */
dudmuck 0:8f0d0ae0a077 475 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
dudmuck 0:8f0d0ae0a077 476 {
dudmuck 2:f2d9aa163652 477 static uint8_t fail_count = 0;
dudmuck 0:8f0d0ae0a077 478 char str[64];
dudmuck 2:f2d9aa163652 479
dudmuck 1:53c30224eda8 480 isr_printf("McpsConfirm ");
dudmuck 0:8f0d0ae0a077 481 if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 482 {
dudmuck 2:f2d9aa163652 483 fail_count = 0;
dudmuck 1:53c30224eda8 484 isr_printf("OK ");
dudmuck 0:8f0d0ae0a077 485 switch( mcpsConfirm->McpsRequest )
dudmuck 0:8f0d0ae0a077 486 {
dudmuck 0:8f0d0ae0a077 487 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 488 {
dudmuck 1:53c30224eda8 489 isr_printf("UNCONFIRMED");
dudmuck 0:8f0d0ae0a077 490 // Check Datarate
dudmuck 0:8f0d0ae0a077 491 // Check TxPower
dudmuck 0:8f0d0ae0a077 492 break;
dudmuck 0:8f0d0ae0a077 493 }
dudmuck 0:8f0d0ae0a077 494 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 495 {
dudmuck 1:53c30224eda8 496 isr_printf("CONFIRMED");
dudmuck 0:8f0d0ae0a077 497 // Check Datarate
dudmuck 0:8f0d0ae0a077 498 // Check TxPower
dudmuck 0:8f0d0ae0a077 499 // Check AckReceived
dudmuck 0:8f0d0ae0a077 500 // Check NbTrials
dudmuck 0:8f0d0ae0a077 501 LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived;
dudmuck 0:8f0d0ae0a077 502 break;
dudmuck 0:8f0d0ae0a077 503 }
dudmuck 0:8f0d0ae0a077 504 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 505 {
dudmuck 0:8f0d0ae0a077 506 break;
dudmuck 0:8f0d0ae0a077 507 }
dudmuck 0:8f0d0ae0a077 508 default:
dudmuck 0:8f0d0ae0a077 509 break;
dudmuck 0:8f0d0ae0a077 510 }
dudmuck 0:8f0d0ae0a077 511 //LoRaMacUplinkStatus.Datarate = mcpsConfirm->Datarate;
dudmuck 0:8f0d0ae0a077 512 LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter;
dudmuck 0:8f0d0ae0a077 513
dudmuck 0:8f0d0ae0a077 514 } else {
dudmuck 0:8f0d0ae0a077 515 LoRaMacEventInfoStatus_to_string(mcpsConfirm->Status, str);
dudmuck 1:53c30224eda8 516 isr_printf("%s ", str);
dudmuck 0:8f0d0ae0a077 517
dudmuck 0:8f0d0ae0a077 518 /* mcpsIndication may not come. last uplink done, send another uplink */
dudmuck 12:ed33c53afcaf 519 if (jumper_in.read()) { /* jumper installed: auto uplink */
dudmuck 17:3215f12051f9 520 TxNextPacketTimeout.attach_us(&send_uplink, 100000);
dudmuck 12:ed33c53afcaf 521 }
dudmuck 16:915815632c1f 522
dudmuck 2:f2d9aa163652 523 if (++fail_count > 10) {
dudmuck 2:f2d9aa163652 524 /* cause re-join */
dudmuck 2:f2d9aa163652 525 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 526 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 2:f2d9aa163652 527 mibReq.Param.IsNetworkJoined = false;
dudmuck 2:f2d9aa163652 528 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 16:915815632c1f 529 fail_count = 0;
dudmuck 26:8227a4edb216 530 #ifdef SENSORS
dudmuck 26:8227a4edb216 531 sensor_ticker.detach();
dudmuck 26:8227a4edb216 532 #endif
dudmuck 2:f2d9aa163652 533 }
dudmuck 0:8f0d0ae0a077 534 }
dudmuck 0:8f0d0ae0a077 535
dudmuck 1:53c30224eda8 536 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 537 }
dudmuck 0:8f0d0ae0a077 538
dudmuck 0:8f0d0ae0a077 539 /*!
dudmuck 0:8f0d0ae0a077 540 * \brief MCPS-Indication event function
dudmuck 0:8f0d0ae0a077 541 *
dudmuck 0:8f0d0ae0a077 542 * \param [IN] mcpsIndication - Pointer to the indication structure,
dudmuck 0:8f0d0ae0a077 543 * containing indication attributes.
dudmuck 0:8f0d0ae0a077 544 */
dudmuck 0:8f0d0ae0a077 545 static void McpsIndication( McpsIndication_t *mcpsIndication )
dudmuck 0:8f0d0ae0a077 546 {
dudmuck 11:4c337f5bbe4c 547 char str[64];
dudmuck 22:999a7e7698a8 548 MibRequestConfirm_t mibReq;
dudmuck 22:999a7e7698a8 549
dudmuck 1:53c30224eda8 550 isr_printf("McpsIndication ");
dudmuck 0:8f0d0ae0a077 551
dudmuck 0:8f0d0ae0a077 552 /* last uplink done, send another uplink */
dudmuck 16:915815632c1f 553 if (jumper_in.read() && mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_STOP) {
dudmuck 16:915815632c1f 554 /* jumper installed: auto uplink */
dudmuck 17:3215f12051f9 555 TxNextPacketTimeout.attach_us(&send_uplink, 100000);
dudmuck 12:ed33c53afcaf 556 }
dudmuck 0:8f0d0ae0a077 557
dudmuck 0:8f0d0ae0a077 558 if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 559 {
dudmuck 11:4c337f5bbe4c 560 LoRaMacEventInfoStatus_to_string(mcpsIndication->Status, str);
dudmuck 11:4c337f5bbe4c 561 isr_printf("%s\r\n", str);
dudmuck 0:8f0d0ae0a077 562 return;
dudmuck 0:8f0d0ae0a077 563 }
dudmuck 0:8f0d0ae0a077 564
dudmuck 0:8f0d0ae0a077 565 awaiting_mcps_indic = false;
dudmuck 0:8f0d0ae0a077 566
dudmuck 0:8f0d0ae0a077 567 switch( mcpsIndication->McpsIndication )
dudmuck 0:8f0d0ae0a077 568 {
dudmuck 5:c108560af4c3 569 /* this refers to the downlink from gateway, not the uplink that was sent to it */
dudmuck 0:8f0d0ae0a077 570 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 571 {
dudmuck 1:53c30224eda8 572 isr_printf("UNCONFIRMED ");
dudmuck 0:8f0d0ae0a077 573 break;
dudmuck 0:8f0d0ae0a077 574 }
dudmuck 0:8f0d0ae0a077 575 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 576 {
dudmuck 5:c108560af4c3 577 /* downlink has requested Ack */
dudmuck 1:53c30224eda8 578 isr_printf("CONFIRMED ");
dudmuck 0:8f0d0ae0a077 579 break;
dudmuck 0:8f0d0ae0a077 580 }
dudmuck 0:8f0d0ae0a077 581 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 582 {
dudmuck 0:8f0d0ae0a077 583 break;
dudmuck 0:8f0d0ae0a077 584 }
dudmuck 0:8f0d0ae0a077 585 case MCPS_MULTICAST:
dudmuck 0:8f0d0ae0a077 586 {
dudmuck 10:00997daeb0c0 587 isr_printf("MCPS_MULTICAST ");
dudmuck 12:ed33c53afcaf 588 /*if (mcpsIndication->RxData) {
dudmuck 12:ed33c53afcaf 589 }*/
dudmuck 0:8f0d0ae0a077 590 break;
dudmuck 0:8f0d0ae0a077 591 }
dudmuck 0:8f0d0ae0a077 592 default:
dudmuck 0:8f0d0ae0a077 593 break;
dudmuck 0:8f0d0ae0a077 594 }
dudmuck 0:8f0d0ae0a077 595
dudmuck 0:8f0d0ae0a077 596 // Check Multicast
dudmuck 0:8f0d0ae0a077 597 // Check Port
dudmuck 0:8f0d0ae0a077 598 // Check Datarate
dudmuck 0:8f0d0ae0a077 599 // Check FramePending
dudmuck 0:8f0d0ae0a077 600 // Check Buffer
dudmuck 0:8f0d0ae0a077 601 // Check BufferSize
dudmuck 0:8f0d0ae0a077 602 // Check Rssi
dudmuck 0:8f0d0ae0a077 603 // Check Snr
dudmuck 0:8f0d0ae0a077 604 // Check RxSlot
dudmuck 0:8f0d0ae0a077 605 LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi;
dudmuck 0:8f0d0ae0a077 606 if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
dudmuck 0:8f0d0ae0a077 607 {
dudmuck 0:8f0d0ae0a077 608 // Invert and divide by 4
dudmuck 0:8f0d0ae0a077 609 LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 610 LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 611 }
dudmuck 0:8f0d0ae0a077 612 else
dudmuck 0:8f0d0ae0a077 613 {
dudmuck 0:8f0d0ae0a077 614 // Divide by 4
dudmuck 0:8f0d0ae0a077 615 LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 616 }
dudmuck 0:8f0d0ae0a077 617 LoRaMacDownlinkStatus.DownlinkCounter++;
dudmuck 0:8f0d0ae0a077 618 LoRaMacDownlinkStatus.RxData = mcpsIndication->RxData;
dudmuck 0:8f0d0ae0a077 619 LoRaMacDownlinkStatus.Port = mcpsIndication->Port;
dudmuck 0:8f0d0ae0a077 620 LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer;
dudmuck 0:8f0d0ae0a077 621 LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize;
dudmuck 0:8f0d0ae0a077 622
dudmuck 0:8f0d0ae0a077 623 if( mcpsIndication->RxData == true )
dudmuck 0:8f0d0ae0a077 624 {
dudmuck 0:8f0d0ae0a077 625 int i;
dudmuck 1:53c30224eda8 626 isr_printf("RxData %u ", mcpsIndication->BufferSize);
dudmuck 0:8f0d0ae0a077 627 for (i = 0; i < mcpsIndication->BufferSize; i++) {
dudmuck 1:53c30224eda8 628 isr_printf("%02x ", mcpsIndication->Buffer[i]);
dudmuck 0:8f0d0ae0a077 629 }
dudmuck 1:53c30224eda8 630 isr_printf("\r\n");
dudmuck 12:ed33c53afcaf 631
dudmuck 12:ed33c53afcaf 632 switch (mcpsIndication->Buffer[0]) {
dudmuck 12:ed33c53afcaf 633 default:
dudmuck 12:ed33c53afcaf 634 case CMD_NONE: break;
dudmuck 23:a862b5601663 635 #if defined (ENABLE_RGB)
dudmuck 12:ed33c53afcaf 636 case CMD_LED_RGB:
dudmuck 12:ed33c53afcaf 637 rgb.setColorRGB(0,
dudmuck 12:ed33c53afcaf 638 mcpsIndication->Buffer[1], // R
dudmuck 12:ed33c53afcaf 639 mcpsIndication->Buffer[2], // G
dudmuck 12:ed33c53afcaf 640 mcpsIndication->Buffer[3] // B
dudmuck 12:ed33c53afcaf 641 );
dudmuck 16:915815632c1f 642 isr_printf("rgb %u %u %u\r\n",
dudmuck 16:915815632c1f 643 mcpsIndication->Buffer[1],
dudmuck 16:915815632c1f 644 mcpsIndication->Buffer[2],
dudmuck 16:915815632c1f 645 mcpsIndication->Buffer[3]
dudmuck 16:915815632c1f 646 );
dudmuck 12:ed33c53afcaf 647 break;
dudmuck 23:a862b5601663 648 #endif /* ENABLE_RGB */
dudmuck 23:a862b5601663 649 #if defined(SENSORS)
dudmuck 12:ed33c53afcaf 650 case CMD_GPIO_OUT:
dudmuck 12:ed33c53afcaf 651 pc6_out = mcpsIndication->Buffer[1];
dudmuck 16:915815632c1f 652 isr_printf("gpo %d\r\n", mcpsIndication->Buffer[1]);
dudmuck 16:915815632c1f 653 break;
dudmuck 18:9ac71c0eb70d 654 case CMD_PWM:
dudmuck 18:9ac71c0eb70d 655 pwm.period(1.0 / mcpsIndication->Buffer[1]);
dudmuck 18:9ac71c0eb70d 656 pwm.write(mcpsIndication->Buffer[2] / 255.0);
dudmuck 18:9ac71c0eb70d 657 isr_printf("pwm %u %u\r\n", mcpsIndication->Buffer[1], mcpsIndication->Buffer[2]);
dudmuck 22:999a7e7698a8 658 break;
dudmuck 23:a862b5601663 659 #endif /* SENSORS */
dudmuck 22:999a7e7698a8 660 case CMD_TX_POWER:
dudmuck 22:999a7e7698a8 661 isr_printf("txp %u\r\n", mcpsIndication->Buffer[1]);
dudmuck 22:999a7e7698a8 662 mibReq.Type = MIB_CHANNELS_TX_POWER;
dudmuck 22:999a7e7698a8 663 mibReq.Param.ChannelsTxPower = mcpsIndication->Buffer[1];
dudmuck 22:999a7e7698a8 664 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 12:ed33c53afcaf 665 break;
dudmuck 12:ed33c53afcaf 666 } // ..switch (mcpsIndication->Buffer[3])
dudmuck 0:8f0d0ae0a077 667
dudmuck 0:8f0d0ae0a077 668 switch( mcpsIndication->Port )
dudmuck 0:8f0d0ae0a077 669 {
dudmuck 0:8f0d0ae0a077 670 case 1: // The application LED can be controlled on port 1 or 2
dudmuck 0:8f0d0ae0a077 671 case 2:
dudmuck 0:8f0d0ae0a077 672 if( mcpsIndication->BufferSize == 1 )
dudmuck 0:8f0d0ae0a077 673 {
dudmuck 0:8f0d0ae0a077 674 AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
dudmuck 0:8f0d0ae0a077 675 //Led3StateChanged = true;
dudmuck 0:8f0d0ae0a077 676 }
dudmuck 0:8f0d0ae0a077 677 break;
dudmuck 0:8f0d0ae0a077 678 default:
dudmuck 0:8f0d0ae0a077 679 break;
dudmuck 0:8f0d0ae0a077 680 }
dudmuck 0:8f0d0ae0a077 681 }
dudmuck 16:915815632c1f 682
dudmuck 16:915815632c1f 683 if (mcpsIndication->Status == LORAMAC_EVENT_INFO_STATUS_STOP) {
dudmuck 17:3215f12051f9 684 isr_printf(" STOP-SCC");
dudmuck 17:3215f12051f9 685 TxNextPacketTimeout.detach();
dudmuck 16:915815632c1f 686 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 16:915815632c1f 687 }
dudmuck 17:3215f12051f9 688
dudmuck 17:3215f12051f9 689 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 690 }
dudmuck 0:8f0d0ae0a077 691
dudmuck 0:8f0d0ae0a077 692 /*!
dudmuck 0:8f0d0ae0a077 693 * \brief MLME-Confirm event function
dudmuck 0:8f0d0ae0a077 694 *
dudmuck 0:8f0d0ae0a077 695 * \param [IN] mlmeConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 696 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 697 */
dudmuck 0:8f0d0ae0a077 698 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
dudmuck 0:8f0d0ae0a077 699 {
dudmuck 16:915815632c1f 700 char str[64];
dudmuck 16:915815632c1f 701 LoRaMacEventInfoStatus_to_string(mlmeConfirm->Status, str);
dudmuck 16:915815632c1f 702 isr_printf("MlmeConfirm %s ", str);
dudmuck 16:915815632c1f 703
dudmuck 0:8f0d0ae0a077 704 switch( mlmeConfirm->MlmeRequest )
dudmuck 0:8f0d0ae0a077 705 {
dudmuck 0:8f0d0ae0a077 706 case MLME_JOIN:
dudmuck 0:8f0d0ae0a077 707 {
dudmuck 1:53c30224eda8 708 isr_printf("MLME_JOIN ");
dudmuck 0:8f0d0ae0a077 709 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 710 {
dudmuck 0:8f0d0ae0a077 711 // Status is OK, node has joined the network
dudmuck 0:8f0d0ae0a077 712 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 26:8227a4edb216 713 #ifdef SENSORS
dudmuck 26:8227a4edb216 714 sensor_ticker.attach_us(&sensor_poll, 1000000);
dudmuck 26:8227a4edb216 715 sensor_in_idx = 0;
dudmuck 26:8227a4edb216 716 sensor_out_idx = 0;
dudmuck 27:c8b432b2a4a8 717 sample_seqnum = 0;
dudmuck 26:8227a4edb216 718 #endif
dudmuck 2:f2d9aa163652 719 missed_count = 0;
dudmuck 16:915815632c1f 720 if (jumper_in.read()) /* jumper installed: auto uplink */
dudmuck 17:3215f12051f9 721 TxNextPacketTimeout.attach_us(&send_uplink, 100000);
dudmuck 0:8f0d0ae0a077 722 }
dudmuck 0:8f0d0ae0a077 723 else
dudmuck 0:8f0d0ae0a077 724 {
dudmuck 0:8f0d0ae0a077 725 // Join was not successful. Try to join again
dudmuck 0:8f0d0ae0a077 726 DeviceState = DEVICE_STATE_JOIN;
dudmuck 0:8f0d0ae0a077 727 }
dudmuck 0:8f0d0ae0a077 728 break;
dudmuck 0:8f0d0ae0a077 729 }
dudmuck 0:8f0d0ae0a077 730 case MLME_LINK_CHECK:
dudmuck 0:8f0d0ae0a077 731 {
dudmuck 1:53c30224eda8 732 isr_printf("LINK_CHECK");
dudmuck 0:8f0d0ae0a077 733 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 734 {
dudmuck 0:8f0d0ae0a077 735 // Check DemodMargin
dudmuck 0:8f0d0ae0a077 736 //mlmeConfirm->DemodMargin;
dudmuck 0:8f0d0ae0a077 737 // Check NbGateways
dudmuck 0:8f0d0ae0a077 738 //mlmeConfirm->NbGateways;
dudmuck 0:8f0d0ae0a077 739 }
dudmuck 0:8f0d0ae0a077 740 break;
dudmuck 0:8f0d0ae0a077 741 }
dudmuck 0:8f0d0ae0a077 742 default:
dudmuck 0:8f0d0ae0a077 743 break;
dudmuck 0:8f0d0ae0a077 744 }
dudmuck 17:3215f12051f9 745
dudmuck 1:53c30224eda8 746 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 747 }
dudmuck 0:8f0d0ae0a077 748
dudmuck 0:8f0d0ae0a077 749
dudmuck 0:8f0d0ae0a077 750 static void MlmeIndication( MlmeIndication_t *MlmeIndication )
dudmuck 0:8f0d0ae0a077 751 {
dudmuck 0:8f0d0ae0a077 752 char str[64];
dudmuck 0:8f0d0ae0a077 753
dudmuck 1:53c30224eda8 754 isr_printf("MlmeIndication ");
dudmuck 0:8f0d0ae0a077 755 switch( MlmeIndication->MlmeIndication )
dudmuck 0:8f0d0ae0a077 756 {
dudmuck 0:8f0d0ae0a077 757 case MLME_BEACON:
dudmuck 0:8f0d0ae0a077 758 {
dudmuck 2:f2d9aa163652 759 isr_printf("missed:%u BEACON ", missed_count);
dudmuck 0:8f0d0ae0a077 760 LoRaMacEventInfoStatus_to_string(MlmeIndication->Status, str);
dudmuck 1:53c30224eda8 761 isr_printf("%s ", str);
dudmuck 16:915815632c1f 762
dudmuck 0:8f0d0ae0a077 763 if (send_at_beacon) {
dudmuck 17:3215f12051f9 764 TxNextPacketTimeout.attach_us(&send_uplink, 100000);
dudmuck 0:8f0d0ae0a077 765 send_at_beacon = false;
dudmuck 0:8f0d0ae0a077 766 }
dudmuck 16:915815632c1f 767
dudmuck 2:f2d9aa163652 768 if (LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED == MlmeIndication->Status)
dudmuck 2:f2d9aa163652 769 missed_count = 0;
dudmuck 16:915815632c1f 770 else {
dudmuck 16:915815632c1f 771 if (++missed_count > 4) {
dudmuck 16:915815632c1f 772 /* cause re-join */
dudmuck 16:915815632c1f 773 LoRaMacStatus_t status;
dudmuck 16:915815632c1f 774 MibRequestConfirm_t mibReq;
dudmuck 26:8227a4edb216 775 #ifdef SENSORS
dudmuck 26:8227a4edb216 776 sensor_ticker.detach();
dudmuck 26:8227a4edb216 777 #endif
dudmuck 16:915815632c1f 778 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 16:915815632c1f 779 mibReq.Param.IsNetworkJoined = false;
dudmuck 16:915815632c1f 780 status = LoRaMacMibSetRequestConfirm(&mibReq);
dudmuck 16:915815632c1f 781 if (status != LORAMAC_STATUS_OK)
dudmuck 16:915815632c1f 782 DeviceState = DEVICE_STATE_REJOIN;
dudmuck 16:915815632c1f 783
dudmuck 16:915815632c1f 784 LoRaMacStatus_to_string(status, str);
dudmuck 16:915815632c1f 785 isr_printf("app-rejoin %s\r\n", str);
dudmuck 17:3215f12051f9 786 TxNextPacketTimeout.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 16:915815632c1f 787 }
dudmuck 2:f2d9aa163652 788 }
dudmuck 0:8f0d0ae0a077 789 break;
dudmuck 0:8f0d0ae0a077 790
dudmuck 0:8f0d0ae0a077 791 }
dudmuck 10:00997daeb0c0 792 case MLME_TXDONE:
dudmuck 10:00997daeb0c0 793 isr_printf("MLME_TXDONE ");
dudmuck 10:00997daeb0c0 794 break;
dudmuck 0:8f0d0ae0a077 795 default:
dudmuck 1:53c30224eda8 796 isr_printf("<%d> ", MlmeIndication->MlmeIndication);
dudmuck 0:8f0d0ae0a077 797 break;
dudmuck 0:8f0d0ae0a077 798 }
dudmuck 0:8f0d0ae0a077 799
dudmuck 1:53c30224eda8 800 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 801 }
dudmuck 0:8f0d0ae0a077 802
dudmuck 0:8f0d0ae0a077 803 void
dudmuck 0:8f0d0ae0a077 804 send_pcbuf_uplink()
dudmuck 0:8f0d0ae0a077 805 {
dudmuck 0:8f0d0ae0a077 806 bool ret;
dudmuck 0:8f0d0ae0a077 807 memcpy(AppData, pcbuf, pcbuf_len);
dudmuck 0:8f0d0ae0a077 808 AppDataSize = pcbuf_len;
dudmuck 0:8f0d0ae0a077 809
dudmuck 12:ed33c53afcaf 810 ret = SendFrame(TEXT_PORT);
dudmuck 1:53c30224eda8 811 isr_printf("%d = SendFrame()\r\n", ret);
dudmuck 0:8f0d0ae0a077 812 }
dudmuck 0:8f0d0ae0a077 813
dudmuck 10:00997daeb0c0 814
dudmuck 0:8f0d0ae0a077 815 void cmd_status(uint8_t idx)
dudmuck 0:8f0d0ae0a077 816 {
dudmuck 2:f2d9aa163652 817 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 818
dudmuck 2:f2d9aa163652 819 isr_printf("DevEUI ");
dudmuck 2:f2d9aa163652 820 for (int i = 0; i < 8; i++)
dudmuck 2:f2d9aa163652 821 isr_printf("%02x ", DevEui[i]);
dudmuck 2:f2d9aa163652 822 mibReq.Type = MIB_DEV_ADDR;
dudmuck 2:f2d9aa163652 823 LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 2:f2d9aa163652 824 isr_printf(", DevAddr:%x\r\n", mibReq.Param.DevAddr);
dudmuck 2:f2d9aa163652 825
dudmuck 23:a862b5601663 826 #if defined(SENSORS)
dudmuck 23:a862b5601663 827 #ifdef TYPE_ABZ
dudmuck 23:a862b5601663 828 isr_printf("a0:%u a2:%u\r\n", a0.read_u16(), a2.read_u16());
dudmuck 23:a862b5601663 829 #else
dudmuck 23:a862b5601663 830 isr_printf("a1:%u a3:%u\r\n", a1.read_u16(), a3.read_u16());
dudmuck 23:a862b5601663 831 #endif
dudmuck 25:fed9d5b77183 832 isr_printf("button:%d ", user_button.read());
dudmuck 10:00997daeb0c0 833 #endif
dudmuck 17:3215f12051f9 834 isr_printf("DEVICE_STATE_");
dudmuck 17:3215f12051f9 835 switch (DeviceState) {
dudmuck 17:3215f12051f9 836 case DEVICE_STATE_JOIN: printf("JOIN"); break;
dudmuck 17:3215f12051f9 837 case DEVICE_STATE_CYCLE: printf("CYCLE"); break;
dudmuck 17:3215f12051f9 838 case DEVICE_STATE_SLEEP: printf("SLEEP"); break;
dudmuck 17:3215f12051f9 839 case DEVICE_STATE_REJOIN: printf("REJOIN"); break;
dudmuck 18:9ac71c0eb70d 840 case DEVICE_STATE_INIT: printf("INIT"); break;
dudmuck 18:9ac71c0eb70d 841 case DEVICE_STATE_UPLINK: printf("UPLINK"); break;
dudmuck 17:3215f12051f9 842 }
dudmuck 17:3215f12051f9 843 isr_printf(" send_at_beacon:%d\r\n", send_at_beacon);
dudmuck 1:53c30224eda8 844 isr_printf("awaiting_mcps_indic:%d\r\n", awaiting_mcps_indic);
dudmuck 12:ed33c53afcaf 845
dudmuck 0:8f0d0ae0a077 846 loramac_print_status();
dudmuck 10:00997daeb0c0 847
dudmuck 0:8f0d0ae0a077 848 }
dudmuck 0:8f0d0ae0a077 849
dudmuck 0:8f0d0ae0a077 850 void cmd_uplink_length(uint8_t idx)
dudmuck 0:8f0d0ae0a077 851 {
dudmuck 0:8f0d0ae0a077 852 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:8f0d0ae0a077 853 sscanf(pcbuf+idx, "%u", &uplink_length);
dudmuck 0:8f0d0ae0a077 854 }
dudmuck 1:53c30224eda8 855 isr_printf("uplink_length:%u\r\n", uplink_length);
dudmuck 0:8f0d0ae0a077 856 }
dudmuck 0:8f0d0ae0a077 857
dudmuck 23:a862b5601663 858 #if defined(ENABLE_RGB)
dudmuck 12:ed33c53afcaf 859 void cmd_rgb(uint8_t idx)
dudmuck 10:00997daeb0c0 860 {
dudmuck 12:ed33c53afcaf 861 int r, g, b;
dudmuck 12:ed33c53afcaf 862 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 12:ed33c53afcaf 863 rgb.setColorRGB(0, r, g, b);
dudmuck 16:915815632c1f 864 isr_printf("\r\nrgb: %d %d %d\r\n", r, g, b);
dudmuck 16:915815632c1f 865 }
dudmuck 23:a862b5601663 866 #endif /* ENABLE_RGB */
dudmuck 16:915815632c1f 867
dudmuck 23:a862b5601663 868 #if defined(SENSORS)
dudmuck 18:9ac71c0eb70d 869 void cmd_pwm(uint8_t idx)
dudmuck 16:915815632c1f 870 {
dudmuck 18:9ac71c0eb70d 871 float period, duty;
dudmuck 18:9ac71c0eb70d 872 unsigned p, d;
dudmuck 18:9ac71c0eb70d 873
dudmuck 18:9ac71c0eb70d 874 if (sscanf(pcbuf+idx, "%u %u", &p, &d) == 2) {
dudmuck 18:9ac71c0eb70d 875 period = 1.0 / p;
dudmuck 18:9ac71c0eb70d 876 duty = d / 255.0;
dudmuck 18:9ac71c0eb70d 877 pwm.period(period);
dudmuck 18:9ac71c0eb70d 878 pwm.write(duty);
dudmuck 18:9ac71c0eb70d 879 printf("pwm period:%f, duty:%f\r\n", period, duty);
dudmuck 18:9ac71c0eb70d 880 } else
dudmuck 18:9ac71c0eb70d 881 printf("pwm parse fail\r\n");
dudmuck 16:915815632c1f 882 }
dudmuck 16:915815632c1f 883
dudmuck 10:00997daeb0c0 884 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 885
dudmuck 15:9023bf4cf168 886 void cmd_ChannelsTxPower(uint8_t idx)
dudmuck 15:9023bf4cf168 887 {
dudmuck 15:9023bf4cf168 888 MibRequestConfirm_t mibReq;
dudmuck 15:9023bf4cf168 889 unsigned int i;
dudmuck 15:9023bf4cf168 890
dudmuck 15:9023bf4cf168 891 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 15:9023bf4cf168 892 sscanf(pcbuf+idx, "%u", &i);
dudmuck 15:9023bf4cf168 893 mibReq.Type = MIB_CHANNELS_TX_POWER;
dudmuck 15:9023bf4cf168 894 mibReq.Param.ChannelsTxPower = i;
dudmuck 15:9023bf4cf168 895 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 15:9023bf4cf168 896 }
dudmuck 15:9023bf4cf168 897
dudmuck 15:9023bf4cf168 898 mibReq.Type = MIB_CHANNELS_TX_POWER;
dudmuck 15:9023bf4cf168 899 LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 15:9023bf4cf168 900 isr_printf("ChannelsTxPower:%u\r\n", mibReq.Param.ChannelsTxPower);
dudmuck 15:9023bf4cf168 901 }
dudmuck 15:9023bf4cf168 902
dudmuck 0:8f0d0ae0a077 903 typedef struct {
dudmuck 0:8f0d0ae0a077 904 const char* const cmd;
dudmuck 0:8f0d0ae0a077 905 void (*handler)(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 906 const char* const arg_descr;
dudmuck 0:8f0d0ae0a077 907 const char* const description;
dudmuck 0:8f0d0ae0a077 908 } menu_item_t;
dudmuck 0:8f0d0ae0a077 909
dudmuck 0:8f0d0ae0a077 910 void cmd_help(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 911
dudmuck 0:8f0d0ae0a077 912 const menu_item_t menu_items[] =
dudmuck 0:8f0d0ae0a077 913 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:8f0d0ae0a077 914 { "?", cmd_help, "","show available commands"},
dudmuck 0:8f0d0ae0a077 915 { ".", cmd_status, "","print status"},
dudmuck 10:00997daeb0c0 916 { "ul", cmd_uplink_length, "%u","set uplink payload length"},
dudmuck 15:9023bf4cf168 917 { "ctxp", cmd_ChannelsTxPower, "%u","get/set ChannelsTxPower"},
dudmuck 23:a862b5601663 918 #if defined(ENABLE_RGB)
dudmuck 18:9ac71c0eb70d 919 { "rgb", cmd_rgb, "%d %d %d", "set led R G B"},
dudmuck 23:a862b5601663 920 #endif
dudmuck 23:a862b5601663 921 #if defined(SENSORS)
dudmuck 18:9ac71c0eb70d 922 { "p", cmd_pwm, "%u %u", "set pwm period, duty"},
dudmuck 23:a862b5601663 923 #endif /* SENSORS */
dudmuck 0:8f0d0ae0a077 924 { NULL, NULL, NULL, NULL }
dudmuck 0:8f0d0ae0a077 925 };
dudmuck 0:8f0d0ae0a077 926
dudmuck 0:8f0d0ae0a077 927 void cmd_help(uint8_t args_at)
dudmuck 0:8f0d0ae0a077 928 {
dudmuck 0:8f0d0ae0a077 929 int i;
dudmuck 0:8f0d0ae0a077 930
dudmuck 0:8f0d0ae0a077 931 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 1:53c30224eda8 932 isr_printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:8f0d0ae0a077 933 }
dudmuck 0:8f0d0ae0a077 934
dudmuck 0:8f0d0ae0a077 935 }
dudmuck 0:8f0d0ae0a077 936
dudmuck 0:8f0d0ae0a077 937 void
dudmuck 0:8f0d0ae0a077 938 console()
dudmuck 0:8f0d0ae0a077 939 {
dudmuck 0:8f0d0ae0a077 940 bool parsed;
dudmuck 0:8f0d0ae0a077 941 int i;
dudmuck 0:8f0d0ae0a077 942 uint8_t user_cmd_len;
dudmuck 0:8f0d0ae0a077 943
dudmuck 0:8f0d0ae0a077 944 if (pcbuf_len < 0) { // ctrl-C
dudmuck 0:8f0d0ae0a077 945 return;
dudmuck 0:8f0d0ae0a077 946 }
dudmuck 0:8f0d0ae0a077 947 if (pcbuf_len == 0)
dudmuck 0:8f0d0ae0a077 948 return;
dudmuck 0:8f0d0ae0a077 949
dudmuck 1:53c30224eda8 950 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 951
dudmuck 0:8f0d0ae0a077 952 /* get end of user-entered command */
dudmuck 0:8f0d0ae0a077 953 user_cmd_len = 1; // first character can be any character
dudmuck 0:8f0d0ae0a077 954 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:8f0d0ae0a077 955 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:8f0d0ae0a077 956 user_cmd_len = i;
dudmuck 0:8f0d0ae0a077 957 break;
dudmuck 0:8f0d0ae0a077 958 }
dudmuck 0:8f0d0ae0a077 959 }
dudmuck 0:8f0d0ae0a077 960
dudmuck 0:8f0d0ae0a077 961 parsed = false;
dudmuck 0:8f0d0ae0a077 962 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:8f0d0ae0a077 963 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:8f0d0ae0a077 964
dudmuck 0:8f0d0ae0a077 965 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:8f0d0ae0a077 966 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:8f0d0ae0a077 967 mi_len++;
dudmuck 0:8f0d0ae0a077 968 menu_items[i].handler(mi_len);
dudmuck 0:8f0d0ae0a077 969 parsed = true;
dudmuck 0:8f0d0ae0a077 970 break;
dudmuck 0:8f0d0ae0a077 971 }
dudmuck 0:8f0d0ae0a077 972 }
dudmuck 0:8f0d0ae0a077 973
dudmuck 0:8f0d0ae0a077 974 if (!parsed)
dudmuck 0:8f0d0ae0a077 975 send_pcbuf_uplink();
dudmuck 0:8f0d0ae0a077 976
dudmuck 0:8f0d0ae0a077 977 pcbuf_len = 0;
dudmuck 1:53c30224eda8 978 isr_printf("> ");
dudmuck 0:8f0d0ae0a077 979 fflush(stdout);
dudmuck 0:8f0d0ae0a077 980 }
dudmuck 0:8f0d0ae0a077 981
dudmuck 0:8f0d0ae0a077 982 void rx_callback()
dudmuck 0:8f0d0ae0a077 983 {
dudmuck 0:8f0d0ae0a077 984 static uint8_t pcbuf_idx = 0;
dudmuck 0:8f0d0ae0a077 985 static uint8_t prev_len = 0;;
dudmuck 0:8f0d0ae0a077 986 char c = pc.getc();
dudmuck 0:8f0d0ae0a077 987
dudmuck 0:8f0d0ae0a077 988 if (c == 8) {
dudmuck 0:8f0d0ae0a077 989 if (pcbuf_idx > 0) {
dudmuck 0:8f0d0ae0a077 990 pc.putc(8);
dudmuck 0:8f0d0ae0a077 991 pc.putc(' ');
dudmuck 0:8f0d0ae0a077 992 pc.putc(8);
dudmuck 0:8f0d0ae0a077 993 pcbuf_idx--;
dudmuck 0:8f0d0ae0a077 994 }
dudmuck 0:8f0d0ae0a077 995 } else if (c == 3) { // ctrl-C
dudmuck 0:8f0d0ae0a077 996 pcbuf_len = -1;
dudmuck 0:8f0d0ae0a077 997 } else if (c == '\r') {
dudmuck 0:8f0d0ae0a077 998 if (pcbuf_idx == 0) {
dudmuck 0:8f0d0ae0a077 999 pcbuf_len = prev_len;
dudmuck 0:8f0d0ae0a077 1000 } else {
dudmuck 0:8f0d0ae0a077 1001 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:8f0d0ae0a077 1002 prev_len = pcbuf_idx;
dudmuck 0:8f0d0ae0a077 1003 pcbuf_idx = 0;
dudmuck 0:8f0d0ae0a077 1004 pcbuf_len = prev_len;
dudmuck 0:8f0d0ae0a077 1005 }
dudmuck 0:8f0d0ae0a077 1006 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:8f0d0ae0a077 1007 pcbuf[pcbuf_idx++] = c;
dudmuck 0:8f0d0ae0a077 1008 pc.putc(c);
dudmuck 0:8f0d0ae0a077 1009 }
dudmuck 0:8f0d0ae0a077 1010 }
dudmuck 0:8f0d0ae0a077 1011
dudmuck 10:00997daeb0c0 1012 void button_isr()
dudmuck 10:00997daeb0c0 1013 {
dudmuck 10:00997daeb0c0 1014 isr_printf("button_isr\r\n");
dudmuck 19:c3af34457b6d 1015
dudmuck 19:c3af34457b6d 1016 AppPort = SENSOR_PORT;
dudmuck 19:c3af34457b6d 1017 send_uplink();
dudmuck 10:00997daeb0c0 1018 }
dudmuck 10:00997daeb0c0 1019
dudmuck 0:8f0d0ae0a077 1020 /**
dudmuck 0:8f0d0ae0a077 1021 * Main application entry point.
dudmuck 0:8f0d0ae0a077 1022 */
dudmuck 0:8f0d0ae0a077 1023 int main( void )
dudmuck 0:8f0d0ae0a077 1024 {
dudmuck 0:8f0d0ae0a077 1025 LoRaMacPrimitives_t LoRaMacPrimitives;
dudmuck 0:8f0d0ae0a077 1026 LoRaMacCallback_t LoRaMacCallbacks;
dudmuck 0:8f0d0ae0a077 1027 MibRequestConfirm_t mibReq;
dudmuck 0:8f0d0ae0a077 1028
dudmuck 4:d9201410c87b 1029 pc.baud(38400);
dudmuck 7:e238827f0e47 1030 pc.attach(&rx_callback);
dudmuck 16:915815632c1f 1031 isr_printf("\r\nreset %s\r\n", FW_VERS);
dudmuck 10:00997daeb0c0 1032
dudmuck 10:00997daeb0c0 1033 BoardInit( );
dudmuck 10:00997daeb0c0 1034
dudmuck 0:8f0d0ae0a077 1035 DeviceState = DEVICE_STATE_INIT;
dudmuck 10:00997daeb0c0 1036
dudmuck 20:42839629a5dc 1037 while (!user_button) {
dudmuck 20:42839629a5dc 1038 printf("button-lo\r\n");
dudmuck 20:42839629a5dc 1039 wait(0.01);
dudmuck 10:00997daeb0c0 1040 }
dudmuck 20:42839629a5dc 1041 user_button.fall(&button_isr);
dudmuck 12:ed33c53afcaf 1042
dudmuck 23:a862b5601663 1043 #ifdef ENABLE_LUMINOSITY
dudmuck 16:915815632c1f 1044 isr_printf("TSL2561 Sensor ");
dudmuck 12:ed33c53afcaf 1045 if (tsl2561.begin()) {
dudmuck 16:915815632c1f 1046 isr_printf("Found\r\n");
dudmuck 12:ed33c53afcaf 1047 } else {
dudmuck 16:915815632c1f 1048 isr_printf("not-found\r\n");
dudmuck 12:ed33c53afcaf 1049 }
dudmuck 12:ed33c53afcaf 1050
dudmuck 12:ed33c53afcaf 1051 // You can change the gain on the fly, to adapt to brighter/dimmer tsl2561 situations
dudmuck 12:ed33c53afcaf 1052 tsl2561.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations)
dudmuck 12:ed33c53afcaf 1053 //tsl2561.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations)
dudmuck 12:ed33c53afcaf 1054
dudmuck 12:ed33c53afcaf 1055 // Changing the integration time gives you a longer time over which to sense tsl2561
dudmuck 12:ed33c53afcaf 1056 // longer timelines are slower, but are good in very low tsl2561 situtations!
dudmuck 12:ed33c53afcaf 1057 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright tsl2561)
dudmuck 12:ed33c53afcaf 1058 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium tsl2561)
dudmuck 12:ed33c53afcaf 1059 tsl2561.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim tsl2561)
dudmuck 23:a862b5601663 1060 #endif /* ENABLE_LUMINOSITY */
dudmuck 10:00997daeb0c0 1061
dudmuck 10:00997daeb0c0 1062 jumper_out = 1;
dudmuck 10:00997daeb0c0 1063 jumper_in.mode(PullDown);
dudmuck 20:42839629a5dc 1064 pc2 = 0;
dudmuck 0:8f0d0ae0a077 1065
dudmuck 0:8f0d0ae0a077 1066 while( 1 )
dudmuck 0:8f0d0ae0a077 1067 {
dudmuck 0:8f0d0ae0a077 1068 console();
dudmuck 12:ed33c53afcaf 1069
dudmuck 0:8f0d0ae0a077 1070 switch( DeviceState )
dudmuck 0:8f0d0ae0a077 1071 {
dudmuck 0:8f0d0ae0a077 1072 case DEVICE_STATE_INIT:
dudmuck 0:8f0d0ae0a077 1073 {
dudmuck 1:53c30224eda8 1074 isr_printf("DEVICE_STATE_INIT\r\n");
dudmuck 23:a862b5601663 1075 #if defined(SENSORS)
dudmuck 14:7ac0add1123e 1076 uplink_length = 7;
dudmuck 14:7ac0add1123e 1077 #else
dudmuck 0:8f0d0ae0a077 1078 uplink_length = 2;
dudmuck 14:7ac0add1123e 1079 #endif
dudmuck 0:8f0d0ae0a077 1080 LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
dudmuck 0:8f0d0ae0a077 1081 LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
dudmuck 0:8f0d0ae0a077 1082 LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
dudmuck 0:8f0d0ae0a077 1083 LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
dudmuck 0:8f0d0ae0a077 1084 LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
dudmuck 0:8f0d0ae0a077 1085 if (LORAMAC_STATUS_OK != LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks )) {
dudmuck 1:53c30224eda8 1086 isr_printf("LoRaMacInitialization() failed\r\n");
dudmuck 0:8f0d0ae0a077 1087 for (;;) ;
dudmuck 0:8f0d0ae0a077 1088 }
dudmuck 1:53c30224eda8 1089 isr_printf("INIT-ok\r\n");
dudmuck 0:8f0d0ae0a077 1090
dudmuck 0:8f0d0ae0a077 1091 mibReq.Type = MIB_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 1092 mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 1093 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1094
dudmuck 0:8f0d0ae0a077 1095 LoRaMacDownlinkStatus.DownlinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1096
dudmuck 0:8f0d0ae0a077 1097 DeviceState = DEVICE_STATE_JOIN;
dudmuck 0:8f0d0ae0a077 1098 break;
dudmuck 0:8f0d0ae0a077 1099 }
dudmuck 0:8f0d0ae0a077 1100 case DEVICE_STATE_JOIN:
dudmuck 0:8f0d0ae0a077 1101 {
dudmuck 10:00997daeb0c0 1102 if (jumper_in.read()) /* if jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 1103 send_at_beacon = true;
dudmuck 0:8f0d0ae0a077 1104 #if( OVER_THE_AIR_ACTIVATION != 0 )
dudmuck 0:8f0d0ae0a077 1105 MlmeReq_t mlmeReq;
dudmuck 0:8f0d0ae0a077 1106 // override software definition with hardware value
dudmuck 0:8f0d0ae0a077 1107 BoardGetUniqueId(DevEui);
dudmuck 1:53c30224eda8 1108 isr_printf("DevEUI ");
dudmuck 0:8f0d0ae0a077 1109 for (int i = 0; i < 8; i++)
dudmuck 1:53c30224eda8 1110 isr_printf("%02x ", DevEui[i]);
dudmuck 1:53c30224eda8 1111 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 1112
dudmuck 0:8f0d0ae0a077 1113 mlmeReq.Type = MLME_JOIN;
dudmuck 0:8f0d0ae0a077 1114
dudmuck 0:8f0d0ae0a077 1115 mlmeReq.Req.Join.DevEui = DevEui;
dudmuck 0:8f0d0ae0a077 1116 mlmeReq.Req.Join.AppEui = AppEui;
dudmuck 0:8f0d0ae0a077 1117 mlmeReq.Req.Join.AppKey = AppKey;
dudmuck 0:8f0d0ae0a077 1118 mlmeReq.Req.Join.NbTrials = 255;
dudmuck 0:8f0d0ae0a077 1119
dudmuck 16:915815632c1f 1120 LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
dudmuck 16:915815632c1f 1121 if (status != LORAMAC_STATUS_OK) {
dudmuck 16:915815632c1f 1122 char str[48];
dudmuck 16:915815632c1f 1123 LoRaMacStatus_to_string(status, str);
dudmuck 16:915815632c1f 1124 isr_printf("join-req-failed:%s\r\n", str);
dudmuck 0:8f0d0ae0a077 1125 }
dudmuck 0:8f0d0ae0a077 1126 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1127 #else
dudmuck 0:8f0d0ae0a077 1128 mibReq.Type = MIB_NET_ID;
dudmuck 0:8f0d0ae0a077 1129 mibReq.Param.NetID = LORAWAN_NETWORK_ID;
dudmuck 0:8f0d0ae0a077 1130 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1131
dudmuck 0:8f0d0ae0a077 1132 mibReq.Type = MIB_DEV_ADDR;
dudmuck 0:8f0d0ae0a077 1133 mibReq.Param.DevAddr = DevAddr;
dudmuck 0:8f0d0ae0a077 1134 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1135
dudmuck 0:8f0d0ae0a077 1136 mibReq.Type = MIB_NWK_SKEY;
dudmuck 0:8f0d0ae0a077 1137 mibReq.Param.NwkSKey = NwkSKey;
dudmuck 0:8f0d0ae0a077 1138 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1139
dudmuck 0:8f0d0ae0a077 1140 mibReq.Type = MIB_APP_SKEY;
dudmuck 0:8f0d0ae0a077 1141 mibReq.Param.AppSKey = AppSKey;
dudmuck 0:8f0d0ae0a077 1142 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1143
dudmuck 0:8f0d0ae0a077 1144 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 0:8f0d0ae0a077 1145 mibReq.Param.IsNetworkJoined = true;
dudmuck 0:8f0d0ae0a077 1146 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1147 #endif
dudmuck 21:500ff43d8424 1148 join_retry = false;
dudmuck 0:8f0d0ae0a077 1149 break;
dudmuck 0:8f0d0ae0a077 1150 }
dudmuck 0:8f0d0ae0a077 1151 case DEVICE_STATE_CYCLE:
dudmuck 0:8f0d0ae0a077 1152 {
dudmuck 0:8f0d0ae0a077 1153 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1154
dudmuck 0:8f0d0ae0a077 1155 // Schedule next packet transmission
dudmuck 17:3215f12051f9 1156 TxNextPacketTimeout.attach_us(&OnTxNextPacketTimerEvent, TxDutyCycleTime * 1000);
dudmuck 0:8f0d0ae0a077 1157 break;
dudmuck 0:8f0d0ae0a077 1158 }
dudmuck 0:8f0d0ae0a077 1159 case DEVICE_STATE_SLEEP:
dudmuck 0:8f0d0ae0a077 1160 {
dudmuck 20:42839629a5dc 1161 bottom_half();
dudmuck 20:42839629a5dc 1162 LoRaMacBottomHalf();
dudmuck 0:8f0d0ae0a077 1163 // Wake up through events
dudmuck 20:42839629a5dc 1164 pc2 = 1;
dudmuck 20:42839629a5dc 1165 sleep();
dudmuck 20:42839629a5dc 1166 pc2 = 0;
dudmuck 0:8f0d0ae0a077 1167 break;
dudmuck 0:8f0d0ae0a077 1168 }
dudmuck 18:9ac71c0eb70d 1169 case DEVICE_STATE_UPLINK:
dudmuck 18:9ac71c0eb70d 1170 PrepareTxFrame(AppPort);
dudmuck 18:9ac71c0eb70d 1171 SendFrame(AppPort);
dudmuck 18:9ac71c0eb70d 1172 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 18:9ac71c0eb70d 1173 break;
dudmuck 0:8f0d0ae0a077 1174 default:
dudmuck 0:8f0d0ae0a077 1175 {
dudmuck 0:8f0d0ae0a077 1176 DeviceState = DEVICE_STATE_INIT;
dudmuck 0:8f0d0ae0a077 1177 break;
dudmuck 0:8f0d0ae0a077 1178 }
dudmuck 0:8f0d0ae0a077 1179 }
dudmuck 1:53c30224eda8 1180
dudmuck 1:53c30224eda8 1181 bottom_half();
dudmuck 20:42839629a5dc 1182 LoRaMacBottomHalf();
dudmuck 1:53c30224eda8 1183
dudmuck 21:500ff43d8424 1184 if (join_retry) {
dudmuck 21:500ff43d8424 1185 isr_printf("join_retry\r\n");
dudmuck 21:500ff43d8424 1186 DeviceState = DEVICE_STATE_JOIN;
dudmuck 21:500ff43d8424 1187 join_retry = false;
dudmuck 21:500ff43d8424 1188 }
dudmuck 21:500ff43d8424 1189
dudmuck 1:53c30224eda8 1190 } // ..while( 1 )
dudmuck 0:8f0d0ae0a077 1191 }