end node on synchronous star LoRa network.

Dependencies:   SX127x sx12xx_hal TSL2561

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

This project for use with LoRaWAN_singlechannel_gateway project.

Alternately gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Network description is at gateway project page. Synchronous star network.

Hardware Support

This project supports SX1276 and SX1272, sx126x kit, sx126x shield, and sx128x 2.4GHz. The ST board B-L072Z-LRWAN1 is also supported (TypeABZ module). When B-L072Z-LRWAN1 target is selected, TARGET_DISCO_L072CZ_LRWAN1 is defined by tools, allowing correct radio driver configuration for this platform. Alternately, any mbed board that can use LoRa radio shield board should work, but NUCLEO boards are tested.

End-node Unique ID

DevEUI is created from CPU serial number. AppEUI and AppKey are declared as software constants.

End-node Configuration

Data rate definition LORAMAC_DEFAULT_DATARATE configured in LoRaMac-definitions.h. See gateway project page for configuration of gateway.
LoRaWAN addressing is configured in Comissioning.h; only OTA mode is functional.
Header file board/lora_config.h, selects application layer options (i.e. sensors) to be compiled in.

Serial Interface

Serial port operates at 115200bps.
Application layer single_us915_main.cpp User button triggers uplink (i.e. blue button on nucleo board), or jumper enables continuously sends repeated uplink packets. The MAC layer holds each uplink request until the allocated timeslot.

commandargumentsdescription
?-print available commands
. (period)-print status (DevEUI, DevAddr, etc)
ullength integerset payload length of test uplink packets

sensor demo

Selected grove sensors may be plugged into SX1272 shield.
To enable, edit lora_config.h to define SENSORS.

Sensor connections on SX1272MB2xAS:

D8 D9: buttonRX TX: (unused)A3 A4: Rotary Angle Sensor
D6 D7: RGB LEDSCL SDA: digital light sensorA1 A2: Rotary Angle Sensor

Digital input pin, state reported via uplink: PC8
Digital output pin, controlled via downlink: PC6
PWM out: PB_10

Jumper enables auto-repeated transmit: PC10 and PC12 on NUCLEO board, located on end of morpho headers nearby JP4.

Committer:
dudmuck
Date:
Mon Aug 07 13:01:48 2017 -0700
Revision:
22:999a7e7698a8
Parent:
21:500ff43d8424
Child:
23:a862b5601663
add remote tx-power-index control

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