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:
Wed Aug 09 23:41:10 2017 +0000
Revision:
24:94ea42eb6b9e
Parent:
23:a862b5601663
Child:
25:fed9d5b77183
sx1276 driver: support all arduino form factor.  User button on murata-discovery board.

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