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 02 18:47:08 2017 +0000
Revision:
19:c3af34457b6d
Parent:
18:9ac71c0eb70d
Child:
20:42839629a5dc
button_isr runs with jumper installed

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