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:
Thu Jul 27 17:53:37 2017 +0000
Revision:
16:915815632c1f
Parent:
15:9023bf4cf168
Child:
17:3215f12051f9
simplify MAC beacon timer

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 16:915815632c1f 36 PwmOut pwm(PB_10);
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 0:8f0d0ae0a077 137 LowPowerTimeout TxNextPacketTimer;
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 * Indicates if a new packet can be sent
dudmuck 0:8f0d0ae0a077 148 */
dudmuck 0:8f0d0ae0a077 149 static bool NextTx = true;
dudmuck 0:8f0d0ae0a077 150
dudmuck 0:8f0d0ae0a077 151 /*!
dudmuck 0:8f0d0ae0a077 152 * Device states
dudmuck 0:8f0d0ae0a077 153 */
dudmuck 0:8f0d0ae0a077 154 static enum eDeviceState
dudmuck 0:8f0d0ae0a077 155 {
dudmuck 0:8f0d0ae0a077 156 DEVICE_STATE_INIT,
dudmuck 0:8f0d0ae0a077 157 DEVICE_STATE_JOIN,
dudmuck 0:8f0d0ae0a077 158 DEVICE_STATE_SEND,
dudmuck 0:8f0d0ae0a077 159 DEVICE_STATE_CYCLE,
dudmuck 16:915815632c1f 160 DEVICE_STATE_SLEEP,
dudmuck 16:915815632c1f 161 DEVICE_STATE_REJOIN
dudmuck 0:8f0d0ae0a077 162 }DeviceState;
dudmuck 0:8f0d0ae0a077 163
dudmuck 0:8f0d0ae0a077 164 /*!
dudmuck 0:8f0d0ae0a077 165 * Strucure containing the Uplink status
dudmuck 0:8f0d0ae0a077 166 */
dudmuck 0:8f0d0ae0a077 167 struct sLoRaMacUplinkStatus
dudmuck 0:8f0d0ae0a077 168 {
dudmuck 0:8f0d0ae0a077 169 uint8_t Acked;
dudmuck 0:8f0d0ae0a077 170 //int8_t Datarate;
dudmuck 0:8f0d0ae0a077 171 uint16_t UplinkCounter;
dudmuck 0:8f0d0ae0a077 172 uint8_t Port;
dudmuck 0:8f0d0ae0a077 173 uint8_t *Buffer;
dudmuck 0:8f0d0ae0a077 174 uint8_t BufferSize;
dudmuck 0:8f0d0ae0a077 175 }LoRaMacUplinkStatus;
dudmuck 0:8f0d0ae0a077 176 //volatile bool UplinkStatusUpdated = false;
dudmuck 0:8f0d0ae0a077 177
dudmuck 0:8f0d0ae0a077 178 /*!
dudmuck 0:8f0d0ae0a077 179 * Strucure containing the Downlink status
dudmuck 0:8f0d0ae0a077 180 */
dudmuck 0:8f0d0ae0a077 181 struct sLoRaMacDownlinkStatus
dudmuck 0:8f0d0ae0a077 182 {
dudmuck 0:8f0d0ae0a077 183 int16_t Rssi;
dudmuck 0:8f0d0ae0a077 184 int8_t Snr;
dudmuck 0:8f0d0ae0a077 185 uint16_t DownlinkCounter;
dudmuck 0:8f0d0ae0a077 186 bool RxData;
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 }LoRaMacDownlinkStatus;
dudmuck 0:8f0d0ae0a077 191
dudmuck 2:f2d9aa163652 192 static uint8_t missed_count;
dudmuck 2:f2d9aa163652 193
dudmuck 0:8f0d0ae0a077 194
dudmuck 0:8f0d0ae0a077 195 /*!
dudmuck 0:8f0d0ae0a077 196 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 197 */
dudmuck 0:8f0d0ae0a077 198 static void PrepareTxFrame( uint8_t port )
dudmuck 0:8f0d0ae0a077 199 {
dudmuck 0:8f0d0ae0a077 200 switch( port )
dudmuck 0:8f0d0ae0a077 201 {
dudmuck 0:8f0d0ae0a077 202 case 15:
dudmuck 0:8f0d0ae0a077 203 {
dudmuck 0:8f0d0ae0a077 204 AppData[0] = AppLedStateOn;
dudmuck 0:8f0d0ae0a077 205 if( IsTxConfirmed == true )
dudmuck 0:8f0d0ae0a077 206 {
dudmuck 0:8f0d0ae0a077 207 AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
dudmuck 0:8f0d0ae0a077 208 AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter;
dudmuck 0:8f0d0ae0a077 209 AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8;
dudmuck 0:8f0d0ae0a077 210 AppData[4] = LoRaMacDownlinkStatus.Rssi;
dudmuck 0:8f0d0ae0a077 211 AppData[5] = LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 212 }
dudmuck 0:8f0d0ae0a077 213 }
dudmuck 0:8f0d0ae0a077 214 break;
dudmuck 11:4c337f5bbe4c 215 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 10:00997daeb0c0 216 case SENSOR_PORT:
dudmuck 12:ed33c53afcaf 217 {
dudmuck 12:ed33c53afcaf 218 uint16_t x = tsl2561.getLuminosity(TSL2561_VISIBLE);
dudmuck 12:ed33c53afcaf 219 uint16_t a_1 = a1.read_u16();
dudmuck 12:ed33c53afcaf 220 uint16_t a_3 = a3.read_u16();
dudmuck 12:ed33c53afcaf 221 uint8_t status;
dudmuck 12:ed33c53afcaf 222 status = pc8_in.read();
dudmuck 12:ed33c53afcaf 223 status <<= 1;
dudmuck 12:ed33c53afcaf 224 status |= pc6_out.read();
dudmuck 12:ed33c53afcaf 225 AppData[0] = a_1 >> 8;
dudmuck 12:ed33c53afcaf 226 AppData[1] = a_1 & 0xff;
dudmuck 12:ed33c53afcaf 227 AppData[2] = a_3 >> 8;
dudmuck 12:ed33c53afcaf 228 AppData[3] = a_3 & 0xff;
dudmuck 12:ed33c53afcaf 229 AppData[4] = x >> 8;
dudmuck 12:ed33c53afcaf 230 AppData[5] = x & 0xff;
dudmuck 12:ed33c53afcaf 231 AppData[6] = status;
dudmuck 14:7ac0add1123e 232 AppDataSize = uplink_length;
dudmuck 12:ed33c53afcaf 233 //printf("visible:%u\r\n", x);
dudmuck 12:ed33c53afcaf 234 }
dudmuck 10:00997daeb0c0 235 break;
dudmuck 12:ed33c53afcaf 236 #endif /* SENSORS && ENABLE_SX1272 */
dudmuck 0:8f0d0ae0a077 237 default:
dudmuck 0:8f0d0ae0a077 238 break;
dudmuck 0:8f0d0ae0a077 239 }
dudmuck 0:8f0d0ae0a077 240 }
dudmuck 0:8f0d0ae0a077 241
dudmuck 0:8f0d0ae0a077 242 void
dudmuck 0:8f0d0ae0a077 243 LoRaMacEventInfoStatus_to_string(LoRaMacEventInfoStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 244 {
dudmuck 0:8f0d0ae0a077 245 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 246
dudmuck 0:8f0d0ae0a077 247 switch (status) {
dudmuck 0:8f0d0ae0a077 248 case LORAMAC_EVENT_INFO_STATUS_RX_ERROR: ptr = "RX_ERROR"; break;
dudmuck 0:8f0d0ae0a077 249 case LORAMAC_EVENT_INFO_STATUS_OK: ptr = "OK"; break;
dudmuck 2:f2d9aa163652 250 case LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE: ptr = "ERROR_RX_MTYPE"; break;
dudmuck 2:f2d9aa163652 251 case LORAMAC_EVENT_INFO_STATUS_ERROR_SEND: ptr = "ERROR_SEND"; break;
dudmuck 2:f2d9aa163652 252 case LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT: ptr = "ERROR_JOIN_ACCEPT"; break;
dudmuck 2:f2d9aa163652 253 case LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ: ptr = "ERROR_MLMEREQ"; break;
dudmuck 2:f2d9aa163652 254 case LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ: ptr = "ERROR_MCPSREQ"; break;
dudmuck 2:f2d9aa163652 255 //case LORAMAC_EVENT_INFO_STATUS_ERROR: ptr = "ERROR"; break;
dudmuck 2:f2d9aa163652 256
dudmuck 0:8f0d0ae0a077 257 case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: ptr = "TX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 258 case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT: ptr = "RX_TIMEOUT"; break;
dudmuck 0:8f0d0ae0a077 259 case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL: ptr = "JOIN_FAIL"; break;
dudmuck 0:8f0d0ae0a077 260 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED: ptr = "DOWNLINK_REPEATED"; break;
dudmuck 0:8f0d0ae0a077 261 case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: ptr = "TX_DR_PAYLOAD_SIZE_ERROR"; break;
dudmuck 0:8f0d0ae0a077 262 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS: ptr = "DOWNLINK_TOO_MANY_FRAMES_LOSS"; break;
dudmuck 0:8f0d0ae0a077 263 case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL: ptr = "ADDRESS_FAIL"; break;
dudmuck 0:8f0d0ae0a077 264 case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL: ptr = "MIC_FAIL"; break;
dudmuck 0:8f0d0ae0a077 265 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED: ptr = "BEACON_LOCKED"; break;
dudmuck 0:8f0d0ae0a077 266 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOST: ptr = "BEACON_LOST"; break;
dudmuck 0:8f0d0ae0a077 267 case LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND: ptr = "BEACON_NOT_FOUND"; break;
dudmuck 16:915815632c1f 268 case LORAMAC_EVENT_INFO_STATUS_ERROR_INCOMPLETE: ptr = "INCOMPLETE"; break;
dudmuck 16:915815632c1f 269 case LORAMAC_EVENT_INFO_STATUS_STOP: ptr = "STOP"; break;
dudmuck 0:8f0d0ae0a077 270 }
dudmuck 0:8f0d0ae0a077 271
dudmuck 0:8f0d0ae0a077 272 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 273 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 274 }
dudmuck 0:8f0d0ae0a077 275
dudmuck 0:8f0d0ae0a077 276 void
dudmuck 0:8f0d0ae0a077 277 LoRaMacStatus_to_string(LoRaMacStatus_t status, char* dst)
dudmuck 0:8f0d0ae0a077 278 {
dudmuck 0:8f0d0ae0a077 279 const char* ptr = NULL;
dudmuck 0:8f0d0ae0a077 280
dudmuck 0:8f0d0ae0a077 281 switch (status) {
dudmuck 0:8f0d0ae0a077 282 case LORAMAC_STATUS_OK: ptr = "OK"; break;
dudmuck 0:8f0d0ae0a077 283 case LORAMAC_STATUS_BUSY: ptr = "BUSY"; break;
dudmuck 0:8f0d0ae0a077 284 case LORAMAC_STATUS_SERVICE_UNKNOWN: ptr = "SERVICE_UNKNOWN"; break;
dudmuck 0:8f0d0ae0a077 285 case LORAMAC_STATUS_PARAMETER_INVALID: ptr = "PARAMETER_INVALID"; break;
dudmuck 0:8f0d0ae0a077 286 case LORAMAC_STATUS_FREQUENCY_INVALID: ptr = "FREQUENCY_INVALID"; break;
dudmuck 0:8f0d0ae0a077 287 case LORAMAC_STATUS_DATARATE_INVALID: ptr = "DATARATE_INVALID"; break;
dudmuck 0:8f0d0ae0a077 288 case LORAMAC_STATUS_FREQ_AND_DR_INVALID: ptr = "FREQ_AND_DR_INVALID"; break;
dudmuck 0:8f0d0ae0a077 289 case LORAMAC_STATUS_NO_NETWORK_JOINED: ptr = "NO_NETWORK_JOINED"; break;
dudmuck 0:8f0d0ae0a077 290 case LORAMAC_STATUS_LENGTH_ERROR: ptr = "LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 291 case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR: ptr = "MAC_CMD_LENGTH_ERROR"; break;
dudmuck 0:8f0d0ae0a077 292 case LORAMAC_STATUS_DEVICE_OFF: ptr = "DEVICE_OFF"; break;
dudmuck 0:8f0d0ae0a077 293 }
dudmuck 0:8f0d0ae0a077 294 if (ptr != NULL)
dudmuck 0:8f0d0ae0a077 295 strcpy(dst, ptr);
dudmuck 0:8f0d0ae0a077 296 }
dudmuck 0:8f0d0ae0a077 297
dudmuck 0:8f0d0ae0a077 298 /*!
dudmuck 5:c108560af4c3 299 * \brief Function executed on TxNextPacket Timeout event
dudmuck 5:c108560af4c3 300 */
dudmuck 5:c108560af4c3 301 static void OnTxNextPacketTimerEvent( void )
dudmuck 5:c108560af4c3 302 {
dudmuck 5:c108560af4c3 303 MibRequestConfirm_t mibReq;
dudmuck 5:c108560af4c3 304 LoRaMacStatus_t status;
dudmuck 16:915815632c1f 305
dudmuck 16:915815632c1f 306 if (DeviceState == DEVICE_STATE_REJOIN) {
dudmuck 16:915815632c1f 307 isr_printf("unjoin\r\n");
dudmuck 16:915815632c1f 308 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 16:915815632c1f 309 mibReq.Param.IsNetworkJoined = false;
dudmuck 16:915815632c1f 310 if (LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK) {
dudmuck 16:915815632c1f 311 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, 500000);
dudmuck 16:915815632c1f 312 return;
dudmuck 16:915815632c1f 313 }
dudmuck 16:915815632c1f 314 }
dudmuck 5:c108560af4c3 315
dudmuck 5:c108560af4c3 316 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 5:c108560af4c3 317 status = LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 5:c108560af4c3 318
dudmuck 16:915815632c1f 319 isr_printf("OnTxNextPacketTimerEvent() ");
dudmuck 5:c108560af4c3 320 if( status == LORAMAC_STATUS_OK )
dudmuck 5:c108560af4c3 321 {
dudmuck 16:915815632c1f 322 NextTx = true;
dudmuck 5:c108560af4c3 323 if( mibReq.Param.IsNetworkJoined == true )
dudmuck 5:c108560af4c3 324 {
dudmuck 5:c108560af4c3 325 DeviceState = DEVICE_STATE_SEND;
dudmuck 16:915815632c1f 326 isr_printf("send");
dudmuck 5:c108560af4c3 327 }
dudmuck 5:c108560af4c3 328 else
dudmuck 5:c108560af4c3 329 {
dudmuck 16:915815632c1f 330 isr_printf("join");
dudmuck 5:c108560af4c3 331 DeviceState = DEVICE_STATE_JOIN;
dudmuck 5:c108560af4c3 332 }
dudmuck 5:c108560af4c3 333 }
dudmuck 16:915815632c1f 334 isr_printf("\r\n");
dudmuck 5:c108560af4c3 335 }
dudmuck 5:c108560af4c3 336
dudmuck 5:c108560af4c3 337 /*!
dudmuck 0:8f0d0ae0a077 338 * \brief Prepares the payload of the frame
dudmuck 0:8f0d0ae0a077 339 *
dudmuck 0:8f0d0ae0a077 340 * \retval [0: frame could be send, 1: error]
dudmuck 0:8f0d0ae0a077 341 */
dudmuck 12:ed33c53afcaf 342 static bool SendFrame( uint8_t port )
dudmuck 0:8f0d0ae0a077 343 {
dudmuck 0:8f0d0ae0a077 344 McpsReq_t mcpsReq;
dudmuck 0:8f0d0ae0a077 345 LoRaMacTxInfo_t txInfo;
dudmuck 0:8f0d0ae0a077 346 LoRaMacStatus_t status;
dudmuck 0:8f0d0ae0a077 347 char str[64];
dudmuck 0:8f0d0ae0a077 348
dudmuck 0:8f0d0ae0a077 349 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 350 {
dudmuck 0:8f0d0ae0a077 351 // Send empty frame in order to flush MAC commands
dudmuck 0:8f0d0ae0a077 352 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 0:8f0d0ae0a077 353 mcpsReq.Req.Unconfirmed.fBuffer = NULL;
dudmuck 0:8f0d0ae0a077 354 mcpsReq.Req.Unconfirmed.fBufferSize = 0;
dudmuck 0:8f0d0ae0a077 355
dudmuck 0:8f0d0ae0a077 356 LoRaMacUplinkStatus.Acked = false;
dudmuck 0:8f0d0ae0a077 357 LoRaMacUplinkStatus.Port = 0;
dudmuck 0:8f0d0ae0a077 358 LoRaMacUplinkStatus.Buffer = NULL;
dudmuck 0:8f0d0ae0a077 359 LoRaMacUplinkStatus.BufferSize = 0;
dudmuck 0:8f0d0ae0a077 360 }
dudmuck 0:8f0d0ae0a077 361 else
dudmuck 0:8f0d0ae0a077 362 {
dudmuck 0:8f0d0ae0a077 363 LoRaMacUplinkStatus.Acked = false;
dudmuck 12:ed33c53afcaf 364 LoRaMacUplinkStatus.Port = port;
dudmuck 0:8f0d0ae0a077 365 LoRaMacUplinkStatus.Buffer = AppData;
dudmuck 0:8f0d0ae0a077 366 LoRaMacUplinkStatus.BufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 367
dudmuck 0:8f0d0ae0a077 368 if( IsTxConfirmed == false )
dudmuck 0:8f0d0ae0a077 369 {
dudmuck 0:8f0d0ae0a077 370 mcpsReq.Type = MCPS_UNCONFIRMED;
dudmuck 12:ed33c53afcaf 371 mcpsReq.Req.Unconfirmed.fPort = port;
dudmuck 0:8f0d0ae0a077 372 mcpsReq.Req.Unconfirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 373 mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 374 //mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 375 }
dudmuck 0:8f0d0ae0a077 376 else
dudmuck 0:8f0d0ae0a077 377 {
dudmuck 0:8f0d0ae0a077 378 mcpsReq.Type = MCPS_CONFIRMED;
dudmuck 12:ed33c53afcaf 379 mcpsReq.Req.Confirmed.fPort = port;
dudmuck 0:8f0d0ae0a077 380 mcpsReq.Req.Confirmed.fBuffer = AppData;
dudmuck 0:8f0d0ae0a077 381 mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
dudmuck 0:8f0d0ae0a077 382 mcpsReq.Req.Confirmed.NbTrials = 8;
dudmuck 0:8f0d0ae0a077 383 //mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
dudmuck 0:8f0d0ae0a077 384 }
dudmuck 0:8f0d0ae0a077 385 }
dudmuck 0:8f0d0ae0a077 386
dudmuck 0:8f0d0ae0a077 387 status = LoRaMacMcpsRequest( &mcpsReq );
dudmuck 0:8f0d0ae0a077 388 if( status == LORAMAC_STATUS_OK )
dudmuck 0:8f0d0ae0a077 389 {
dudmuck 0:8f0d0ae0a077 390 awaiting_mcps_indic = true;
dudmuck 0:8f0d0ae0a077 391 return false;
dudmuck 0:8f0d0ae0a077 392 }
dudmuck 0:8f0d0ae0a077 393 LoRaMacStatus_to_string(status, str);
dudmuck 1:53c30224eda8 394 isr_printf("send failed:%s\r\n", str);
dudmuck 16:915815632c1f 395
dudmuck 16:915815632c1f 396 AppPort = port;
dudmuck 16:915815632c1f 397 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 16:915815632c1f 398
dudmuck 0:8f0d0ae0a077 399 return true;
dudmuck 0:8f0d0ae0a077 400 }
dudmuck 0:8f0d0ae0a077 401
dudmuck 0:8f0d0ae0a077 402 void
dudmuck 0:8f0d0ae0a077 403 send_uplink()
dudmuck 0:8f0d0ae0a077 404 {
dudmuck 0:8f0d0ae0a077 405 AppDataSize = uplink_length;
dudmuck 1:53c30224eda8 406 NextTx = true;
dudmuck 1:53c30224eda8 407 DeviceState = DEVICE_STATE_SEND;
dudmuck 0:8f0d0ae0a077 408 }
dudmuck 0:8f0d0ae0a077 409
dudmuck 0:8f0d0ae0a077 410 /*!
dudmuck 0:8f0d0ae0a077 411 * \brief MCPS-Confirm event function
dudmuck 0:8f0d0ae0a077 412 *
dudmuck 0:8f0d0ae0a077 413 * \param [IN] mcpsConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 414 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 415 */
dudmuck 0:8f0d0ae0a077 416 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
dudmuck 0:8f0d0ae0a077 417 {
dudmuck 2:f2d9aa163652 418 static uint8_t fail_count = 0;
dudmuck 0:8f0d0ae0a077 419 char str[64];
dudmuck 2:f2d9aa163652 420
dudmuck 1:53c30224eda8 421 isr_printf("McpsConfirm ");
dudmuck 0:8f0d0ae0a077 422 if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 423 {
dudmuck 2:f2d9aa163652 424 fail_count = 0;
dudmuck 1:53c30224eda8 425 isr_printf("OK ");
dudmuck 0:8f0d0ae0a077 426 switch( mcpsConfirm->McpsRequest )
dudmuck 0:8f0d0ae0a077 427 {
dudmuck 0:8f0d0ae0a077 428 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 429 {
dudmuck 1:53c30224eda8 430 isr_printf("UNCONFIRMED");
dudmuck 0:8f0d0ae0a077 431 // Check Datarate
dudmuck 0:8f0d0ae0a077 432 // Check TxPower
dudmuck 0:8f0d0ae0a077 433 break;
dudmuck 0:8f0d0ae0a077 434 }
dudmuck 0:8f0d0ae0a077 435 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 436 {
dudmuck 1:53c30224eda8 437 isr_printf("CONFIRMED");
dudmuck 0:8f0d0ae0a077 438 // Check Datarate
dudmuck 0:8f0d0ae0a077 439 // Check TxPower
dudmuck 0:8f0d0ae0a077 440 // Check AckReceived
dudmuck 0:8f0d0ae0a077 441 // Check NbTrials
dudmuck 0:8f0d0ae0a077 442 LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived;
dudmuck 0:8f0d0ae0a077 443 break;
dudmuck 0:8f0d0ae0a077 444 }
dudmuck 0:8f0d0ae0a077 445 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 446 {
dudmuck 0:8f0d0ae0a077 447 break;
dudmuck 0:8f0d0ae0a077 448 }
dudmuck 0:8f0d0ae0a077 449 default:
dudmuck 0:8f0d0ae0a077 450 break;
dudmuck 0:8f0d0ae0a077 451 }
dudmuck 0:8f0d0ae0a077 452 //LoRaMacUplinkStatus.Datarate = mcpsConfirm->Datarate;
dudmuck 0:8f0d0ae0a077 453 LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter;
dudmuck 0:8f0d0ae0a077 454
dudmuck 0:8f0d0ae0a077 455 } else {
dudmuck 0:8f0d0ae0a077 456 LoRaMacEventInfoStatus_to_string(mcpsConfirm->Status, str);
dudmuck 1:53c30224eda8 457 isr_printf("%s ", str);
dudmuck 0:8f0d0ae0a077 458
dudmuck 0:8f0d0ae0a077 459 /* mcpsIndication may not come. last uplink done, send another uplink */
dudmuck 12:ed33c53afcaf 460 if (jumper_in.read()) { /* jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 461 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 12:ed33c53afcaf 462 }
dudmuck 16:915815632c1f 463
dudmuck 2:f2d9aa163652 464 if (++fail_count > 10) {
dudmuck 2:f2d9aa163652 465 /* cause re-join */
dudmuck 2:f2d9aa163652 466 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 467 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 2:f2d9aa163652 468 mibReq.Param.IsNetworkJoined = false;
dudmuck 2:f2d9aa163652 469 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 16:915815632c1f 470 fail_count = 0;
dudmuck 2:f2d9aa163652 471 }
dudmuck 0:8f0d0ae0a077 472 }
dudmuck 0:8f0d0ae0a077 473
dudmuck 0:8f0d0ae0a077 474 NextTx = true;
dudmuck 1:53c30224eda8 475 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 476 }
dudmuck 0:8f0d0ae0a077 477
dudmuck 0:8f0d0ae0a077 478 /*!
dudmuck 0:8f0d0ae0a077 479 * \brief MCPS-Indication event function
dudmuck 0:8f0d0ae0a077 480 *
dudmuck 0:8f0d0ae0a077 481 * \param [IN] mcpsIndication - Pointer to the indication structure,
dudmuck 0:8f0d0ae0a077 482 * containing indication attributes.
dudmuck 0:8f0d0ae0a077 483 */
dudmuck 0:8f0d0ae0a077 484 static void McpsIndication( McpsIndication_t *mcpsIndication )
dudmuck 0:8f0d0ae0a077 485 {
dudmuck 11:4c337f5bbe4c 486 char str[64];
dudmuck 1:53c30224eda8 487 isr_printf("McpsIndication ");
dudmuck 0:8f0d0ae0a077 488
dudmuck 0:8f0d0ae0a077 489 /* last uplink done, send another uplink */
dudmuck 16:915815632c1f 490 if (jumper_in.read() && mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_STOP) {
dudmuck 16:915815632c1f 491 /* jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 492 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 12:ed33c53afcaf 493 }
dudmuck 0:8f0d0ae0a077 494
dudmuck 0:8f0d0ae0a077 495 if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 496 {
dudmuck 11:4c337f5bbe4c 497 LoRaMacEventInfoStatus_to_string(mcpsIndication->Status, str);
dudmuck 11:4c337f5bbe4c 498 isr_printf("%s\r\n", str);
dudmuck 0:8f0d0ae0a077 499 return;
dudmuck 0:8f0d0ae0a077 500 }
dudmuck 0:8f0d0ae0a077 501
dudmuck 0:8f0d0ae0a077 502 awaiting_mcps_indic = false;
dudmuck 0:8f0d0ae0a077 503
dudmuck 0:8f0d0ae0a077 504 switch( mcpsIndication->McpsIndication )
dudmuck 0:8f0d0ae0a077 505 {
dudmuck 5:c108560af4c3 506 /* this refers to the downlink from gateway, not the uplink that was sent to it */
dudmuck 0:8f0d0ae0a077 507 case MCPS_UNCONFIRMED:
dudmuck 0:8f0d0ae0a077 508 {
dudmuck 1:53c30224eda8 509 isr_printf("UNCONFIRMED ");
dudmuck 0:8f0d0ae0a077 510 break;
dudmuck 0:8f0d0ae0a077 511 }
dudmuck 0:8f0d0ae0a077 512 case MCPS_CONFIRMED:
dudmuck 0:8f0d0ae0a077 513 {
dudmuck 5:c108560af4c3 514 /* downlink has requested Ack */
dudmuck 1:53c30224eda8 515 isr_printf("CONFIRMED ");
dudmuck 0:8f0d0ae0a077 516 break;
dudmuck 0:8f0d0ae0a077 517 }
dudmuck 0:8f0d0ae0a077 518 case MCPS_PROPRIETARY:
dudmuck 0:8f0d0ae0a077 519 {
dudmuck 0:8f0d0ae0a077 520 break;
dudmuck 0:8f0d0ae0a077 521 }
dudmuck 0:8f0d0ae0a077 522 case MCPS_MULTICAST:
dudmuck 0:8f0d0ae0a077 523 {
dudmuck 10:00997daeb0c0 524 isr_printf("MCPS_MULTICAST ");
dudmuck 12:ed33c53afcaf 525 /*if (mcpsIndication->RxData) {
dudmuck 12:ed33c53afcaf 526 }*/
dudmuck 0:8f0d0ae0a077 527 break;
dudmuck 0:8f0d0ae0a077 528 }
dudmuck 0:8f0d0ae0a077 529 default:
dudmuck 0:8f0d0ae0a077 530 break;
dudmuck 0:8f0d0ae0a077 531 }
dudmuck 0:8f0d0ae0a077 532
dudmuck 0:8f0d0ae0a077 533 // Check Multicast
dudmuck 0:8f0d0ae0a077 534 // Check Port
dudmuck 0:8f0d0ae0a077 535 // Check Datarate
dudmuck 0:8f0d0ae0a077 536 // Check FramePending
dudmuck 0:8f0d0ae0a077 537 // Check Buffer
dudmuck 0:8f0d0ae0a077 538 // Check BufferSize
dudmuck 0:8f0d0ae0a077 539 // Check Rssi
dudmuck 0:8f0d0ae0a077 540 // Check Snr
dudmuck 0:8f0d0ae0a077 541 // Check RxSlot
dudmuck 0:8f0d0ae0a077 542 LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi;
dudmuck 0:8f0d0ae0a077 543 if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
dudmuck 0:8f0d0ae0a077 544 {
dudmuck 0:8f0d0ae0a077 545 // Invert and divide by 4
dudmuck 0:8f0d0ae0a077 546 LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 547 LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
dudmuck 0:8f0d0ae0a077 548 }
dudmuck 0:8f0d0ae0a077 549 else
dudmuck 0:8f0d0ae0a077 550 {
dudmuck 0:8f0d0ae0a077 551 // Divide by 4
dudmuck 0:8f0d0ae0a077 552 LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2;
dudmuck 0:8f0d0ae0a077 553 }
dudmuck 0:8f0d0ae0a077 554 LoRaMacDownlinkStatus.DownlinkCounter++;
dudmuck 0:8f0d0ae0a077 555 LoRaMacDownlinkStatus.RxData = mcpsIndication->RxData;
dudmuck 0:8f0d0ae0a077 556 LoRaMacDownlinkStatus.Port = mcpsIndication->Port;
dudmuck 0:8f0d0ae0a077 557 LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer;
dudmuck 0:8f0d0ae0a077 558 LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize;
dudmuck 0:8f0d0ae0a077 559
dudmuck 0:8f0d0ae0a077 560 if( mcpsIndication->RxData == true )
dudmuck 0:8f0d0ae0a077 561 {
dudmuck 0:8f0d0ae0a077 562 int i;
dudmuck 1:53c30224eda8 563 isr_printf("RxData %u ", mcpsIndication->BufferSize);
dudmuck 0:8f0d0ae0a077 564 for (i = 0; i < mcpsIndication->BufferSize; i++) {
dudmuck 1:53c30224eda8 565 isr_printf("%02x ", mcpsIndication->Buffer[i]);
dudmuck 0:8f0d0ae0a077 566 }
dudmuck 1:53c30224eda8 567 isr_printf("\r\n");
dudmuck 12:ed33c53afcaf 568
dudmuck 12:ed33c53afcaf 569 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 12:ed33c53afcaf 570 switch (mcpsIndication->Buffer[0]) {
dudmuck 16:915815632c1f 571 float* fptr;
dudmuck 12:ed33c53afcaf 572 default:
dudmuck 12:ed33c53afcaf 573 case CMD_NONE: break;
dudmuck 12:ed33c53afcaf 574 case CMD_LED_RGB:
dudmuck 12:ed33c53afcaf 575 rgb.setColorRGB(0,
dudmuck 12:ed33c53afcaf 576 mcpsIndication->Buffer[1], // R
dudmuck 12:ed33c53afcaf 577 mcpsIndication->Buffer[2], // G
dudmuck 12:ed33c53afcaf 578 mcpsIndication->Buffer[3] // B
dudmuck 12:ed33c53afcaf 579 );
dudmuck 16:915815632c1f 580 isr_printf("rgb %u %u %u\r\n",
dudmuck 16:915815632c1f 581 mcpsIndication->Buffer[1],
dudmuck 16:915815632c1f 582 mcpsIndication->Buffer[2],
dudmuck 16:915815632c1f 583 mcpsIndication->Buffer[3]
dudmuck 16:915815632c1f 584 );
dudmuck 12:ed33c53afcaf 585 break;
dudmuck 12:ed33c53afcaf 586 case CMD_GPIO_OUT:
dudmuck 12:ed33c53afcaf 587 pc6_out = mcpsIndication->Buffer[1];
dudmuck 16:915815632c1f 588 isr_printf("gpo %d\r\n", mcpsIndication->Buffer[1]);
dudmuck 16:915815632c1f 589 break;
dudmuck 16:915815632c1f 590 case CMD_PWM_PERIOD:
dudmuck 16:915815632c1f 591 fptr = (float*)&mcpsIndication->Buffer[1];
dudmuck 16:915815632c1f 592 pwm.period(*fptr);
dudmuck 16:915815632c1f 593 isr_printf("pwm period:%f\r\n", *fptr);
dudmuck 16:915815632c1f 594 break;
dudmuck 16:915815632c1f 595 case CMD_PWM_DUTY:
dudmuck 16:915815632c1f 596 fptr = (float*)&mcpsIndication->Buffer[1];
dudmuck 16:915815632c1f 597 pwm.write(*fptr);
dudmuck 16:915815632c1f 598 isr_printf("pwm duty:%f\r\n", *fptr);
dudmuck 12:ed33c53afcaf 599 break;
dudmuck 12:ed33c53afcaf 600 } // ..switch (mcpsIndication->Buffer[3])
dudmuck 12:ed33c53afcaf 601 #endif /* SENSORS && ENABLE_SX1272 */
dudmuck 0:8f0d0ae0a077 602
dudmuck 0:8f0d0ae0a077 603 switch( mcpsIndication->Port )
dudmuck 0:8f0d0ae0a077 604 {
dudmuck 0:8f0d0ae0a077 605 case 1: // The application LED can be controlled on port 1 or 2
dudmuck 0:8f0d0ae0a077 606 case 2:
dudmuck 0:8f0d0ae0a077 607 if( mcpsIndication->BufferSize == 1 )
dudmuck 0:8f0d0ae0a077 608 {
dudmuck 0:8f0d0ae0a077 609 AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
dudmuck 0:8f0d0ae0a077 610 //Led3StateChanged = true;
dudmuck 0:8f0d0ae0a077 611 }
dudmuck 0:8f0d0ae0a077 612 break;
dudmuck 0:8f0d0ae0a077 613 default:
dudmuck 0:8f0d0ae0a077 614 break;
dudmuck 0:8f0d0ae0a077 615 }
dudmuck 0:8f0d0ae0a077 616 }
dudmuck 0:8f0d0ae0a077 617
dudmuck 1:53c30224eda8 618 isr_printf("\r\n");
dudmuck 16:915815632c1f 619
dudmuck 16:915815632c1f 620 if (mcpsIndication->Status == LORAMAC_EVENT_INFO_STATUS_STOP) {
dudmuck 16:915815632c1f 621 TxNextPacketTimer.detach();
dudmuck 16:915815632c1f 622 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 16:915815632c1f 623 }
dudmuck 0:8f0d0ae0a077 624 }
dudmuck 0:8f0d0ae0a077 625
dudmuck 0:8f0d0ae0a077 626 /*!
dudmuck 0:8f0d0ae0a077 627 * \brief MLME-Confirm event function
dudmuck 0:8f0d0ae0a077 628 *
dudmuck 0:8f0d0ae0a077 629 * \param [IN] mlmeConfirm - Pointer to the confirm structure,
dudmuck 0:8f0d0ae0a077 630 * containing confirm attributes.
dudmuck 0:8f0d0ae0a077 631 */
dudmuck 0:8f0d0ae0a077 632 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
dudmuck 0:8f0d0ae0a077 633 {
dudmuck 16:915815632c1f 634 char str[64];
dudmuck 16:915815632c1f 635 LoRaMacEventInfoStatus_to_string(mlmeConfirm->Status, str);
dudmuck 16:915815632c1f 636 isr_printf("MlmeConfirm %s ", str);
dudmuck 16:915815632c1f 637
dudmuck 0:8f0d0ae0a077 638 switch( mlmeConfirm->MlmeRequest )
dudmuck 0:8f0d0ae0a077 639 {
dudmuck 0:8f0d0ae0a077 640 case MLME_JOIN:
dudmuck 0:8f0d0ae0a077 641 {
dudmuck 1:53c30224eda8 642 isr_printf("MLME_JOIN ");
dudmuck 0:8f0d0ae0a077 643 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 644 {
dudmuck 0:8f0d0ae0a077 645 // Status is OK, node has joined the network
dudmuck 0:8f0d0ae0a077 646 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 2:f2d9aa163652 647 missed_count = 0;
dudmuck 16:915815632c1f 648 if (jumper_in.read()) /* jumper installed: auto uplink */
dudmuck 16:915815632c1f 649 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 0:8f0d0ae0a077 650 }
dudmuck 0:8f0d0ae0a077 651 else
dudmuck 0:8f0d0ae0a077 652 {
dudmuck 0:8f0d0ae0a077 653 // Join was not successful. Try to join again
dudmuck 0:8f0d0ae0a077 654 DeviceState = DEVICE_STATE_JOIN;
dudmuck 0:8f0d0ae0a077 655 }
dudmuck 0:8f0d0ae0a077 656 break;
dudmuck 0:8f0d0ae0a077 657 }
dudmuck 0:8f0d0ae0a077 658 case MLME_LINK_CHECK:
dudmuck 0:8f0d0ae0a077 659 {
dudmuck 1:53c30224eda8 660 isr_printf("LINK_CHECK");
dudmuck 0:8f0d0ae0a077 661 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
dudmuck 0:8f0d0ae0a077 662 {
dudmuck 0:8f0d0ae0a077 663 // Check DemodMargin
dudmuck 0:8f0d0ae0a077 664 //mlmeConfirm->DemodMargin;
dudmuck 0:8f0d0ae0a077 665 // Check NbGateways
dudmuck 0:8f0d0ae0a077 666 //mlmeConfirm->NbGateways;
dudmuck 0:8f0d0ae0a077 667 }
dudmuck 0:8f0d0ae0a077 668 break;
dudmuck 0:8f0d0ae0a077 669 }
dudmuck 0:8f0d0ae0a077 670 default:
dudmuck 0:8f0d0ae0a077 671 break;
dudmuck 0:8f0d0ae0a077 672 }
dudmuck 0:8f0d0ae0a077 673 NextTx = true;
dudmuck 1:53c30224eda8 674 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 675 }
dudmuck 0:8f0d0ae0a077 676
dudmuck 0:8f0d0ae0a077 677
dudmuck 0:8f0d0ae0a077 678 static void MlmeIndication( MlmeIndication_t *MlmeIndication )
dudmuck 0:8f0d0ae0a077 679 {
dudmuck 0:8f0d0ae0a077 680 char str[64];
dudmuck 0:8f0d0ae0a077 681
dudmuck 1:53c30224eda8 682 isr_printf("MlmeIndication ");
dudmuck 0:8f0d0ae0a077 683 switch( MlmeIndication->MlmeIndication )
dudmuck 0:8f0d0ae0a077 684 {
dudmuck 0:8f0d0ae0a077 685 case MLME_BEACON:
dudmuck 0:8f0d0ae0a077 686 {
dudmuck 2:f2d9aa163652 687 isr_printf("missed:%u BEACON ", missed_count);
dudmuck 0:8f0d0ae0a077 688 LoRaMacEventInfoStatus_to_string(MlmeIndication->Status, str);
dudmuck 1:53c30224eda8 689 isr_printf("%s ", str);
dudmuck 16:915815632c1f 690
dudmuck 0:8f0d0ae0a077 691 if (send_at_beacon) {
dudmuck 0:8f0d0ae0a077 692 TxNextPacketTimer.attach_us(&send_uplink, 100000);
dudmuck 0:8f0d0ae0a077 693 send_at_beacon = false;
dudmuck 0:8f0d0ae0a077 694 }
dudmuck 16:915815632c1f 695
dudmuck 2:f2d9aa163652 696 if (LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED == MlmeIndication->Status)
dudmuck 2:f2d9aa163652 697 missed_count = 0;
dudmuck 16:915815632c1f 698 else {
dudmuck 16:915815632c1f 699 if (++missed_count > 4) {
dudmuck 16:915815632c1f 700 /* cause re-join */
dudmuck 16:915815632c1f 701 LoRaMacStatus_t status;
dudmuck 16:915815632c1f 702 MibRequestConfirm_t mibReq;
dudmuck 16:915815632c1f 703 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 16:915815632c1f 704 mibReq.Param.IsNetworkJoined = false;
dudmuck 16:915815632c1f 705 status = LoRaMacMibSetRequestConfirm(&mibReq);
dudmuck 16:915815632c1f 706 if (status != LORAMAC_STATUS_OK)
dudmuck 16:915815632c1f 707 DeviceState = DEVICE_STATE_REJOIN;
dudmuck 16:915815632c1f 708
dudmuck 16:915815632c1f 709 LoRaMacStatus_to_string(status, str);
dudmuck 16:915815632c1f 710 isr_printf("app-rejoin %s\r\n", str);
dudmuck 16:915815632c1f 711 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, randr(1000000, 5000000) + 1000000);
dudmuck 16:915815632c1f 712 }
dudmuck 2:f2d9aa163652 713 }
dudmuck 0:8f0d0ae0a077 714 break;
dudmuck 0:8f0d0ae0a077 715
dudmuck 0:8f0d0ae0a077 716 }
dudmuck 10:00997daeb0c0 717 case MLME_TXDONE:
dudmuck 10:00997daeb0c0 718 isr_printf("MLME_TXDONE ");
dudmuck 10:00997daeb0c0 719 break;
dudmuck 0:8f0d0ae0a077 720 default:
dudmuck 1:53c30224eda8 721 isr_printf("<%d> ", MlmeIndication->MlmeIndication);
dudmuck 0:8f0d0ae0a077 722 break;
dudmuck 0:8f0d0ae0a077 723 }
dudmuck 0:8f0d0ae0a077 724
dudmuck 1:53c30224eda8 725 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 726 }
dudmuck 0:8f0d0ae0a077 727
dudmuck 0:8f0d0ae0a077 728 void
dudmuck 0:8f0d0ae0a077 729 send_pcbuf_uplink()
dudmuck 0:8f0d0ae0a077 730 {
dudmuck 0:8f0d0ae0a077 731 bool ret;
dudmuck 0:8f0d0ae0a077 732 memcpy(AppData, pcbuf, pcbuf_len);
dudmuck 0:8f0d0ae0a077 733 AppDataSize = pcbuf_len;
dudmuck 0:8f0d0ae0a077 734
dudmuck 12:ed33c53afcaf 735 ret = SendFrame(TEXT_PORT);
dudmuck 1:53c30224eda8 736 isr_printf("%d = SendFrame()\r\n", ret);
dudmuck 0:8f0d0ae0a077 737 }
dudmuck 0:8f0d0ae0a077 738
dudmuck 10:00997daeb0c0 739
dudmuck 0:8f0d0ae0a077 740 void cmd_status(uint8_t idx)
dudmuck 0:8f0d0ae0a077 741 {
dudmuck 2:f2d9aa163652 742 MibRequestConfirm_t mibReq;
dudmuck 2:f2d9aa163652 743
dudmuck 2:f2d9aa163652 744 isr_printf("DevEUI ");
dudmuck 2:f2d9aa163652 745 for (int i = 0; i < 8; i++)
dudmuck 2:f2d9aa163652 746 isr_printf("%02x ", DevEui[i]);
dudmuck 2:f2d9aa163652 747 mibReq.Type = MIB_DEV_ADDR;
dudmuck 2:f2d9aa163652 748 LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 2:f2d9aa163652 749 isr_printf(", DevAddr:%x\r\n", mibReq.Param.DevAddr);
dudmuck 2:f2d9aa163652 750
dudmuck 11:4c337f5bbe4c 751 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 12:ed33c53afcaf 752 isr_printf("a1:%u a3:%u\r\n", a1.read_u16(), a3.read_u16());
dudmuck 12:ed33c53afcaf 753 isr_printf("button:%d,%u ", button.read(), button_cnt);
dudmuck 10:00997daeb0c0 754 #endif
dudmuck 1:53c30224eda8 755 isr_printf("DeviceState:%d\r\n", DeviceState);
dudmuck 1:53c30224eda8 756 isr_printf("send_at_beacon:%d\r\n", send_at_beacon);
dudmuck 1:53c30224eda8 757 isr_printf("awaiting_mcps_indic:%d\r\n", awaiting_mcps_indic);
dudmuck 12:ed33c53afcaf 758
dudmuck 0:8f0d0ae0a077 759 loramac_print_status();
dudmuck 10:00997daeb0c0 760
dudmuck 0:8f0d0ae0a077 761 }
dudmuck 0:8f0d0ae0a077 762
dudmuck 0:8f0d0ae0a077 763 void cmd_uplink_length(uint8_t idx)
dudmuck 0:8f0d0ae0a077 764 {
dudmuck 0:8f0d0ae0a077 765 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:8f0d0ae0a077 766 sscanf(pcbuf+idx, "%u", &uplink_length);
dudmuck 0:8f0d0ae0a077 767 }
dudmuck 1:53c30224eda8 768 isr_printf("uplink_length:%u\r\n", uplink_length);
dudmuck 0:8f0d0ae0a077 769 }
dudmuck 0:8f0d0ae0a077 770
dudmuck 11:4c337f5bbe4c 771 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 12:ed33c53afcaf 772 void cmd_rgb(uint8_t idx)
dudmuck 10:00997daeb0c0 773 {
dudmuck 12:ed33c53afcaf 774 int r, g, b;
dudmuck 12:ed33c53afcaf 775 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 12:ed33c53afcaf 776 rgb.setColorRGB(0, r, g, b);
dudmuck 16:915815632c1f 777 isr_printf("\r\nrgb: %d %d %d\r\n", r, g, b);
dudmuck 16:915815632c1f 778 }
dudmuck 16:915815632c1f 779
dudmuck 16:915815632c1f 780 void cmd_pwm_period(uint8_t idx)
dudmuck 16:915815632c1f 781 {
dudmuck 16:915815632c1f 782 float period;
dudmuck 16:915815632c1f 783 sscanf(pcbuf+idx, "%f", &period);
dudmuck 16:915815632c1f 784 pwm.period(period);
dudmuck 16:915815632c1f 785 printf("pwm period:%f\r\n", period);
dudmuck 10:00997daeb0c0 786 }
dudmuck 16:915815632c1f 787
dudmuck 16:915815632c1f 788 void cmd_pwm_duty(uint8_t idx)
dudmuck 16:915815632c1f 789 {
dudmuck 16:915815632c1f 790 float duty;
dudmuck 16:915815632c1f 791 sscanf(pcbuf+idx, "%f", &duty);
dudmuck 16:915815632c1f 792 pwm.write(duty);
dudmuck 16:915815632c1f 793 printf("pwm duty:%f\r\n", duty);
dudmuck 16:915815632c1f 794 }
dudmuck 16:915815632c1f 795
dudmuck 10:00997daeb0c0 796 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 797
dudmuck 15:9023bf4cf168 798 void cmd_ChannelsTxPower(uint8_t idx)
dudmuck 15:9023bf4cf168 799 {
dudmuck 15:9023bf4cf168 800 MibRequestConfirm_t mibReq;
dudmuck 15:9023bf4cf168 801 unsigned int i;
dudmuck 15:9023bf4cf168 802
dudmuck 15:9023bf4cf168 803 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 15:9023bf4cf168 804 sscanf(pcbuf+idx, "%u", &i);
dudmuck 15:9023bf4cf168 805 mibReq.Type = MIB_CHANNELS_TX_POWER;
dudmuck 15:9023bf4cf168 806 mibReq.Param.ChannelsTxPower = i;
dudmuck 15:9023bf4cf168 807 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 15:9023bf4cf168 808 }
dudmuck 15:9023bf4cf168 809
dudmuck 15:9023bf4cf168 810 mibReq.Type = MIB_CHANNELS_TX_POWER;
dudmuck 15:9023bf4cf168 811 LoRaMacMibGetRequestConfirm( &mibReq );
dudmuck 15:9023bf4cf168 812 isr_printf("ChannelsTxPower:%u\r\n", mibReq.Param.ChannelsTxPower);
dudmuck 15:9023bf4cf168 813 }
dudmuck 15:9023bf4cf168 814
dudmuck 0:8f0d0ae0a077 815 typedef struct {
dudmuck 0:8f0d0ae0a077 816 const char* const cmd;
dudmuck 0:8f0d0ae0a077 817 void (*handler)(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 818 const char* const arg_descr;
dudmuck 0:8f0d0ae0a077 819 const char* const description;
dudmuck 0:8f0d0ae0a077 820 } menu_item_t;
dudmuck 0:8f0d0ae0a077 821
dudmuck 0:8f0d0ae0a077 822 void cmd_help(uint8_t args_at);
dudmuck 0:8f0d0ae0a077 823
dudmuck 0:8f0d0ae0a077 824 const menu_item_t menu_items[] =
dudmuck 0:8f0d0ae0a077 825 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:8f0d0ae0a077 826 { "?", cmd_help, "","show available commands"},
dudmuck 0:8f0d0ae0a077 827 { ".", cmd_status, "","print status"},
dudmuck 10:00997daeb0c0 828 { "ul", cmd_uplink_length, "%u","set uplink payload length"},
dudmuck 15:9023bf4cf168 829 { "ctxp", cmd_ChannelsTxPower, "%u","get/set ChannelsTxPower"},
dudmuck 11:4c337f5bbe4c 830 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 12:ed33c53afcaf 831 { "l", cmd_rgb, "%d %d %d", "set led R G B"},
dudmuck 16:915815632c1f 832 { "pp", cmd_pwm_period, "%f", "set pwm period"},
dudmuck 16:915815632c1f 833 { "pd", cmd_pwm_duty, "%f", "set pwm 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 10:00997daeb0c0 929 if (!jumper_in.read()) {
dudmuck 10:00997daeb0c0 930 /* jumper not installed: manual uplink */
dudmuck 12:ed33c53afcaf 931 AppPort = SENSOR_PORT;
dudmuck 10:00997daeb0c0 932 send_uplink();
dudmuck 10:00997daeb0c0 933 }
dudmuck 10:00997daeb0c0 934 }
dudmuck 10:00997daeb0c0 935 #endif /* SENSORS */
dudmuck 10:00997daeb0c0 936
dudmuck 0:8f0d0ae0a077 937 /**
dudmuck 0:8f0d0ae0a077 938 * Main application entry point.
dudmuck 0:8f0d0ae0a077 939 */
dudmuck 0:8f0d0ae0a077 940 int main( void )
dudmuck 0:8f0d0ae0a077 941 {
dudmuck 12:ed33c53afcaf 942 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 12:ed33c53afcaf 943 uint8_t prev_but;
dudmuck 12:ed33c53afcaf 944 #endif /* SENSORS && ENABLE_SX1272 */
dudmuck 0:8f0d0ae0a077 945 LoRaMacPrimitives_t LoRaMacPrimitives;
dudmuck 0:8f0d0ae0a077 946 LoRaMacCallback_t LoRaMacCallbacks;
dudmuck 0:8f0d0ae0a077 947 MibRequestConfirm_t mibReq;
dudmuck 0:8f0d0ae0a077 948
dudmuck 4:d9201410c87b 949 pc.baud(38400);
dudmuck 7:e238827f0e47 950 pc.attach(&rx_callback);
dudmuck 16:915815632c1f 951 isr_printf("\r\nreset %s\r\n", FW_VERS);
dudmuck 10:00997daeb0c0 952
dudmuck 10:00997daeb0c0 953 BoardInit( );
dudmuck 10:00997daeb0c0 954
dudmuck 0:8f0d0ae0a077 955 DeviceState = DEVICE_STATE_INIT;
dudmuck 10:00997daeb0c0 956
dudmuck 11:4c337f5bbe4c 957 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 10:00997daeb0c0 958 if (button) {
dudmuck 10:00997daeb0c0 959 button.rise(&button_isr);
dudmuck 16:915815632c1f 960 isr_printf("button-rise\r\n");
dudmuck 10:00997daeb0c0 961 } else {
dudmuck 10:00997daeb0c0 962 button.rise(&button_isr);
dudmuck 16:915815632c1f 963 isr_printf("button-fall\r\n");
dudmuck 10:00997daeb0c0 964 }
dudmuck 12:ed33c53afcaf 965 prev_but = button;
dudmuck 12:ed33c53afcaf 966
dudmuck 16:915815632c1f 967 isr_printf("TSL2561 Sensor ");
dudmuck 12:ed33c53afcaf 968 if (tsl2561.begin()) {
dudmuck 16:915815632c1f 969 isr_printf("Found\r\n");
dudmuck 12:ed33c53afcaf 970 } else {
dudmuck 16:915815632c1f 971 isr_printf("not-found\r\n");
dudmuck 12:ed33c53afcaf 972 }
dudmuck 12:ed33c53afcaf 973
dudmuck 12:ed33c53afcaf 974 // You can change the gain on the fly, to adapt to brighter/dimmer tsl2561 situations
dudmuck 12:ed33c53afcaf 975 tsl2561.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations)
dudmuck 12:ed33c53afcaf 976 //tsl2561.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations)
dudmuck 12:ed33c53afcaf 977
dudmuck 12:ed33c53afcaf 978 // Changing the integration time gives you a longer time over which to sense tsl2561
dudmuck 12:ed33c53afcaf 979 // longer timelines are slower, but are good in very low tsl2561 situtations!
dudmuck 12:ed33c53afcaf 980 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright tsl2561)
dudmuck 12:ed33c53afcaf 981 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium tsl2561)
dudmuck 12:ed33c53afcaf 982 tsl2561.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim tsl2561)
dudmuck 12:ed33c53afcaf 983 #endif /* SENSORS && ENABLE_SX1272 */
dudmuck 10:00997daeb0c0 984
dudmuck 10:00997daeb0c0 985 jumper_out = 1;
dudmuck 10:00997daeb0c0 986 jumper_in.mode(PullDown);
dudmuck 0:8f0d0ae0a077 987
dudmuck 0:8f0d0ae0a077 988 while( 1 )
dudmuck 0:8f0d0ae0a077 989 {
dudmuck 0:8f0d0ae0a077 990 console();
dudmuck 12:ed33c53afcaf 991
dudmuck 12:ed33c53afcaf 992 #if defined(SENSORS) && defined(ENABLE_SX1272) && defined(TARGET_NUCLEO_L073RZ)
dudmuck 12:ed33c53afcaf 993 if (prev_but != button) {
dudmuck 12:ed33c53afcaf 994 if (button) {
dudmuck 12:ed33c53afcaf 995 button_isr();
dudmuck 12:ed33c53afcaf 996 }
dudmuck 12:ed33c53afcaf 997 prev_but = button;
dudmuck 12:ed33c53afcaf 998 }
dudmuck 12:ed33c53afcaf 999 #endif
dudmuck 0:8f0d0ae0a077 1000
dudmuck 0:8f0d0ae0a077 1001 switch( DeviceState )
dudmuck 0:8f0d0ae0a077 1002 {
dudmuck 0:8f0d0ae0a077 1003 case DEVICE_STATE_INIT:
dudmuck 0:8f0d0ae0a077 1004 {
dudmuck 1:53c30224eda8 1005 isr_printf("DEVICE_STATE_INIT\r\n");
dudmuck 14:7ac0add1123e 1006 #if defined(SENSORS) && defined(ENABLE_SX1272)
dudmuck 14:7ac0add1123e 1007 uplink_length = 7;
dudmuck 14:7ac0add1123e 1008 #else
dudmuck 0:8f0d0ae0a077 1009 uplink_length = 2;
dudmuck 14:7ac0add1123e 1010 #endif
dudmuck 0:8f0d0ae0a077 1011 LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
dudmuck 0:8f0d0ae0a077 1012 LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
dudmuck 0:8f0d0ae0a077 1013 LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
dudmuck 0:8f0d0ae0a077 1014 LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
dudmuck 0:8f0d0ae0a077 1015 LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
dudmuck 0:8f0d0ae0a077 1016 if (LORAMAC_STATUS_OK != LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks )) {
dudmuck 1:53c30224eda8 1017 isr_printf("LoRaMacInitialization() failed\r\n");
dudmuck 0:8f0d0ae0a077 1018 for (;;) ;
dudmuck 0:8f0d0ae0a077 1019 }
dudmuck 1:53c30224eda8 1020 isr_printf("INIT-ok\r\n");
dudmuck 0:8f0d0ae0a077 1021
dudmuck 0:8f0d0ae0a077 1022 mibReq.Type = MIB_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 1023 mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
dudmuck 0:8f0d0ae0a077 1024 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1025
dudmuck 0:8f0d0ae0a077 1026 LoRaMacDownlinkStatus.DownlinkCounter = 0;
dudmuck 0:8f0d0ae0a077 1027
dudmuck 0:8f0d0ae0a077 1028 DeviceState = DEVICE_STATE_JOIN;
dudmuck 0:8f0d0ae0a077 1029 break;
dudmuck 0:8f0d0ae0a077 1030 }
dudmuck 0:8f0d0ae0a077 1031 case DEVICE_STATE_JOIN:
dudmuck 0:8f0d0ae0a077 1032 {
dudmuck 10:00997daeb0c0 1033 if (jumper_in.read()) /* if jumper installed: auto uplink */
dudmuck 10:00997daeb0c0 1034 send_at_beacon = true;
dudmuck 0:8f0d0ae0a077 1035 #if( OVER_THE_AIR_ACTIVATION != 0 )
dudmuck 0:8f0d0ae0a077 1036 MlmeReq_t mlmeReq;
dudmuck 0:8f0d0ae0a077 1037 // override software definition with hardware value
dudmuck 0:8f0d0ae0a077 1038 BoardGetUniqueId(DevEui);
dudmuck 1:53c30224eda8 1039 isr_printf("DevEUI ");
dudmuck 0:8f0d0ae0a077 1040 for (int i = 0; i < 8; i++)
dudmuck 1:53c30224eda8 1041 isr_printf("%02x ", DevEui[i]);
dudmuck 1:53c30224eda8 1042 isr_printf("\r\n");
dudmuck 0:8f0d0ae0a077 1043
dudmuck 0:8f0d0ae0a077 1044 mlmeReq.Type = MLME_JOIN;
dudmuck 0:8f0d0ae0a077 1045
dudmuck 0:8f0d0ae0a077 1046 mlmeReq.Req.Join.DevEui = DevEui;
dudmuck 0:8f0d0ae0a077 1047 mlmeReq.Req.Join.AppEui = AppEui;
dudmuck 0:8f0d0ae0a077 1048 mlmeReq.Req.Join.AppKey = AppKey;
dudmuck 0:8f0d0ae0a077 1049 mlmeReq.Req.Join.NbTrials = 255;
dudmuck 0:8f0d0ae0a077 1050
dudmuck 16:915815632c1f 1051 LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
dudmuck 16:915815632c1f 1052 if (status != LORAMAC_STATUS_OK) {
dudmuck 16:915815632c1f 1053 char str[48];
dudmuck 16:915815632c1f 1054 LoRaMacStatus_to_string(status, str);
dudmuck 16:915815632c1f 1055 isr_printf("join-req-failed:%s\r\n", str);
dudmuck 0:8f0d0ae0a077 1056 }
dudmuck 0:8f0d0ae0a077 1057 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1058 #else
dudmuck 0:8f0d0ae0a077 1059 mibReq.Type = MIB_NET_ID;
dudmuck 0:8f0d0ae0a077 1060 mibReq.Param.NetID = LORAWAN_NETWORK_ID;
dudmuck 0:8f0d0ae0a077 1061 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1062
dudmuck 0:8f0d0ae0a077 1063 mibReq.Type = MIB_DEV_ADDR;
dudmuck 0:8f0d0ae0a077 1064 mibReq.Param.DevAddr = DevAddr;
dudmuck 0:8f0d0ae0a077 1065 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1066
dudmuck 0:8f0d0ae0a077 1067 mibReq.Type = MIB_NWK_SKEY;
dudmuck 0:8f0d0ae0a077 1068 mibReq.Param.NwkSKey = NwkSKey;
dudmuck 0:8f0d0ae0a077 1069 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1070
dudmuck 0:8f0d0ae0a077 1071 mibReq.Type = MIB_APP_SKEY;
dudmuck 0:8f0d0ae0a077 1072 mibReq.Param.AppSKey = AppSKey;
dudmuck 0:8f0d0ae0a077 1073 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1074
dudmuck 0:8f0d0ae0a077 1075 mibReq.Type = MIB_NETWORK_JOINED;
dudmuck 0:8f0d0ae0a077 1076 mibReq.Param.IsNetworkJoined = true;
dudmuck 0:8f0d0ae0a077 1077 LoRaMacMibSetRequestConfirm( &mibReq );
dudmuck 0:8f0d0ae0a077 1078
dudmuck 0:8f0d0ae0a077 1079 DeviceState = DEVICE_STATE_SEND;
dudmuck 0:8f0d0ae0a077 1080 #endif
dudmuck 0:8f0d0ae0a077 1081 break;
dudmuck 0:8f0d0ae0a077 1082 }
dudmuck 0:8f0d0ae0a077 1083 case DEVICE_STATE_SEND:
dudmuck 0:8f0d0ae0a077 1084 {
dudmuck 0:8f0d0ae0a077 1085 if( NextTx == true )
dudmuck 0:8f0d0ae0a077 1086 {
dudmuck 12:ed33c53afcaf 1087 PrepareTxFrame(AppPort);
dudmuck 0:8f0d0ae0a077 1088
dudmuck 12:ed33c53afcaf 1089 NextTx = SendFrame(AppPort);
dudmuck 0:8f0d0ae0a077 1090 }
dudmuck 2:f2d9aa163652 1091
dudmuck 0:8f0d0ae0a077 1092 // Schedule next packet transmission
dudmuck 0:8f0d0ae0a077 1093 TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
dudmuck 2:f2d9aa163652 1094 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1095 break;
dudmuck 0:8f0d0ae0a077 1096 }
dudmuck 0:8f0d0ae0a077 1097 case DEVICE_STATE_CYCLE:
dudmuck 0:8f0d0ae0a077 1098 {
dudmuck 0:8f0d0ae0a077 1099 DeviceState = DEVICE_STATE_SLEEP;
dudmuck 0:8f0d0ae0a077 1100
dudmuck 0:8f0d0ae0a077 1101 // Schedule next packet transmission
dudmuck 0:8f0d0ae0a077 1102 TxNextPacketTimer.attach_us(&OnTxNextPacketTimerEvent, TxDutyCycleTime * 1000);
dudmuck 0:8f0d0ae0a077 1103 break;
dudmuck 0:8f0d0ae0a077 1104 }
dudmuck 0:8f0d0ae0a077 1105 case DEVICE_STATE_SLEEP:
dudmuck 0:8f0d0ae0a077 1106 {
dudmuck 1:53c30224eda8 1107 //isr_printf("sleep %u\r\n", queue.tick());
dudmuck 0:8f0d0ae0a077 1108 // Wake up through events
dudmuck 0:8f0d0ae0a077 1109 break;
dudmuck 0:8f0d0ae0a077 1110 }
dudmuck 0:8f0d0ae0a077 1111 default:
dudmuck 0:8f0d0ae0a077 1112 {
dudmuck 0:8f0d0ae0a077 1113 DeviceState = DEVICE_STATE_INIT;
dudmuck 0:8f0d0ae0a077 1114 break;
dudmuck 0:8f0d0ae0a077 1115 }
dudmuck 0:8f0d0ae0a077 1116 }
dudmuck 1:53c30224eda8 1117
dudmuck 1:53c30224eda8 1118 bottom_half();
dudmuck 1:53c30224eda8 1119
dudmuck 1:53c30224eda8 1120 } // ..while( 1 )
dudmuck 0:8f0d0ae0a077 1121 }