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:
Tue Aug 08 15:16:37 2017 -0700
Revision:
23:a862b5601663
Parent:
22:999a7e7698a8
Child:
24:94ea42eb6b9e
sx1276 driver: support PaSelect on TYPE_ABZ module

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