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:
Fri Aug 04 13:23:38 2017 -0700
Revision:
20:42839629a5dc
Parent:
19:c3af34457b6d
Child:
21:500ff43d8424
add sleep() call, mbedignore rtos

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