for India band 30dBm LoRa Module, DSPLoRa based on code from Semtech and as modified by Sachin Pukale/ TCL/

Dependencies:   mbed Chainable_RGB_LED DigitDisplay LoRaWAN-lib SX1276Lib

Fork of DSP_LoRaWAN by Akshay Mishra

Committer:
spcores
Date:
Thu Apr 21 10:17:28 2016 +0000
Revision:
2:66f94cef0765
Parent:
1:c365eaf833bb
Child:
3:042ccdf1dd92
With ABP & Smart LED Lamp

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mluis 0:cb80564f40e1 1 /*
mluis 0:cb80564f40e1 2 / _____) _ | |
mluis 0:cb80564f40e1 3 ( (____ _____ ____ _| |_ _____ ____| |__
mluis 0:cb80564f40e1 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
mluis 0:cb80564f40e1 5 _____) ) ____| | | || |_| ____( (___| | | |
mluis 0:cb80564f40e1 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
mluis 0:cb80564f40e1 7 (C)2015 Semtech
mluis 0:cb80564f40e1 8
mluis 0:cb80564f40e1 9 Description: LoRaMac classA device implementation
mluis 0:cb80564f40e1 10
mluis 0:cb80564f40e1 11 License: Revised BSD License, see LICENSE.TXT file include in the project
mluis 0:cb80564f40e1 12
mluis 0:cb80564f40e1 13 Maintainer: Miguel Luis and Gregory Cristian
mluis 0:cb80564f40e1 14 */
mluis 0:cb80564f40e1 15 #include "mbed.h"
mluis 0:cb80564f40e1 16 #include "board.h"
mluis 0:cb80564f40e1 17 #include "radio.h"
mluis 0:cb80564f40e1 18
mluis 0:cb80564f40e1 19 #include "LoRaMac.h"
mluis 0:cb80564f40e1 20 #include "Comissioning.h"
mluis 0:cb80564f40e1 21 #include "SerialDisplay.h"
mluis 0:cb80564f40e1 22 #include "ChainableLED.h"
spcores 2:66f94cef0765 23
spcores 2:66f94cef0765 24 #define SEMTECH_BC_APP 0 //1 : Use Semtech Bootcamp Application
spcores 2:66f94cef0765 25
spcores 2:66f94cef0765 26 #if defined( SEMTECH_BC_APP )
spcores 2:66f94cef0765 27 #include "DigitDisplay.h"
spcores 2:66f94cef0765 28 #endif
spcores 2:66f94cef0765 29
mluis 0:cb80564f40e1 30 /*!
mluis 0:cb80564f40e1 31 * Join requests trials duty cycle.
mluis 0:cb80564f40e1 32 */
mluis 0:cb80564f40e1 33 #define OVER_THE_AIR_ACTIVATION_DUTYCYCLE 10000000 // 10 [s] value in us
mluis 0:cb80564f40e1 34
mluis 0:cb80564f40e1 35 /*!
spcores 2:66f94cef0765 36 * Defines the application data transmission duty cycle. 60s, value in [us].
mluis 0:cb80564f40e1 37 */
spcores 2:66f94cef0765 38 #define APP_TX_DUTYCYCLE 3000000
mluis 0:cb80564f40e1 39
mluis 0:cb80564f40e1 40 /*!
mluis 0:cb80564f40e1 41 * Defines a random delay for application data transmission duty cycle. 1s,
mluis 0:cb80564f40e1 42 * value in [us].
mluis 0:cb80564f40e1 43 */
mluis 0:cb80564f40e1 44 #define APP_TX_DUTYCYCLE_RND 1000000
mluis 0:cb80564f40e1 45
mluis 0:cb80564f40e1 46 /*!
mluis 0:cb80564f40e1 47 * Default mote datarate
mluis 0:cb80564f40e1 48 */
mluis 0:cb80564f40e1 49 #define LORAWAN_DEFAULT_DATARATE DR_5
mluis 0:cb80564f40e1 50
mluis 0:cb80564f40e1 51 /*!
mluis 0:cb80564f40e1 52 * LoRaWAN confirmed messages
mluis 0:cb80564f40e1 53 */
mluis 0:cb80564f40e1 54 #define LORAWAN_CONFIRMED_MSG_ON false
mluis 0:cb80564f40e1 55
mluis 0:cb80564f40e1 56 /*!
mluis 0:cb80564f40e1 57 * LoRaWAN Adaptive Data Rate
mluis 0:cb80564f40e1 58 *
mluis 0:cb80564f40e1 59 * \remark Please note that when ADR is enabled the end-device should be static
mluis 0:cb80564f40e1 60 */
spcores 1:c365eaf833bb 61 #define LORAWAN_ADR_ON 0
mluis 0:cb80564f40e1 62
spcores 1:c365eaf833bb 63 #if defined( USE_BAND_868 ) || defined( USE_BAND_865 )
mluis 0:cb80564f40e1 64
mluis 0:cb80564f40e1 65 #include "LoRaMacTest.h"
mluis 0:cb80564f40e1 66
mluis 0:cb80564f40e1 67 /*!
mluis 0:cb80564f40e1 68 * LoRaWAN ETSI duty cycle control enable/disable
mluis 0:cb80564f40e1 69 *
mluis 0:cb80564f40e1 70 * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
mluis 0:cb80564f40e1 71 */
mluis 0:cb80564f40e1 72 #define LORAWAN_DUTYCYCLE_ON false
mluis 0:cb80564f40e1 73
mluis 0:cb80564f40e1 74 #endif
mluis 0:cb80564f40e1 75
mluis 0:cb80564f40e1 76 /*!
mluis 0:cb80564f40e1 77 * LoRaWAN application port
mluis 0:cb80564f40e1 78 */
spcores 1:c365eaf833bb 79 #define LORAWAN_APP_PORT 5
mluis 0:cb80564f40e1 80
mluis 0:cb80564f40e1 81 /*!
mluis 0:cb80564f40e1 82 * User application data buffer size
mluis 0:cb80564f40e1 83 */
mluis 0:cb80564f40e1 84 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
spcores 1:c365eaf833bb 85 #define LORAWAN_APP_DATA_SIZE 7 //6
mluis 0:cb80564f40e1 86
mluis 0:cb80564f40e1 87 #else
spcores 1:c365eaf833bb 88 #define LORAWAN_APP_DATA_SIZE 6 //5
mluis 0:cb80564f40e1 89
mluis 0:cb80564f40e1 90 #endif
mluis 0:cb80564f40e1 91
mluis 0:cb80564f40e1 92 #if( OVER_THE_AIR_ACTIVATION != 0 )
mluis 0:cb80564f40e1 93
mluis 0:cb80564f40e1 94 static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
mluis 0:cb80564f40e1 95 static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
mluis 0:cb80564f40e1 96 static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
mluis 0:cb80564f40e1 97
mluis 0:cb80564f40e1 98 #else
mluis 0:cb80564f40e1 99
mluis 0:cb80564f40e1 100 static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
mluis 0:cb80564f40e1 101 static uint8_t AppSKey[] = LORAWAN_APPSKEY;
mluis 0:cb80564f40e1 102
mluis 0:cb80564f40e1 103 /*!
mluis 0:cb80564f40e1 104 * Device address
mluis 0:cb80564f40e1 105 */
mluis 0:cb80564f40e1 106 static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
mluis 0:cb80564f40e1 107
mluis 0:cb80564f40e1 108 #endif
mluis 0:cb80564f40e1 109
mluis 0:cb80564f40e1 110 /*!
mluis 0:cb80564f40e1 111 * Application port
mluis 0:cb80564f40e1 112 */
mluis 0:cb80564f40e1 113 static uint8_t AppPort = LORAWAN_APP_PORT;
mluis 0:cb80564f40e1 114
mluis 0:cb80564f40e1 115 /*!
mluis 0:cb80564f40e1 116 * User application data size
mluis 0:cb80564f40e1 117 */
mluis 0:cb80564f40e1 118 static uint8_t AppDataSize = LORAWAN_APP_DATA_SIZE;
mluis 0:cb80564f40e1 119
mluis 0:cb80564f40e1 120 /*!
mluis 0:cb80564f40e1 121 * User application data buffer size
mluis 0:cb80564f40e1 122 */
mluis 0:cb80564f40e1 123 #define LORAWAN_APP_DATA_MAX_SIZE 64
mluis 0:cb80564f40e1 124
mluis 0:cb80564f40e1 125 /*!
mluis 0:cb80564f40e1 126 * User application data
mluis 0:cb80564f40e1 127 */
mluis 0:cb80564f40e1 128 static uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE];
mluis 0:cb80564f40e1 129
mluis 0:cb80564f40e1 130 /*!
mluis 0:cb80564f40e1 131 * Indicates if the node is sending confirmed or unconfirmed messages
mluis 0:cb80564f40e1 132 */
mluis 0:cb80564f40e1 133 static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
mluis 0:cb80564f40e1 134
mluis 0:cb80564f40e1 135 /*!
mluis 0:cb80564f40e1 136 * Defines the application data transmission duty cycle
mluis 0:cb80564f40e1 137 */
mluis 0:cb80564f40e1 138 static uint32_t TxDutyCycleTime;
mluis 0:cb80564f40e1 139
mluis 0:cb80564f40e1 140 /*!
mluis 0:cb80564f40e1 141 * Timer to handle the application data transmission duty cycle
mluis 0:cb80564f40e1 142 */
mluis 0:cb80564f40e1 143 static TimerEvent_t TxNextPacketTimer;
mluis 0:cb80564f40e1 144
mluis 0:cb80564f40e1 145 /*!
mluis 0:cb80564f40e1 146 * Specifies the state of the application LED
mluis 0:cb80564f40e1 147 */
mluis 0:cb80564f40e1 148 static bool AppLedStateOn = false;
mluis 0:cb80564f40e1 149 volatile bool Led3StateChanged = false;
mluis 0:cb80564f40e1 150 /*!
mluis 0:cb80564f40e1 151 * Timer to handle the state of LED1
mluis 0:cb80564f40e1 152 */
mluis 0:cb80564f40e1 153 static TimerEvent_t Led1Timer;
mluis 0:cb80564f40e1 154 volatile bool Led1State = false;
mluis 0:cb80564f40e1 155 volatile bool Led1StateChanged = false;
mluis 0:cb80564f40e1 156 /*!
mluis 0:cb80564f40e1 157 * Timer to handle the state of LED2
mluis 0:cb80564f40e1 158 */
mluis 0:cb80564f40e1 159 static TimerEvent_t Led2Timer;
mluis 0:cb80564f40e1 160 volatile bool Led2State = false;
mluis 0:cb80564f40e1 161 volatile bool Led2StateChanged = false;
mluis 0:cb80564f40e1 162
mluis 0:cb80564f40e1 163 /*!
mluis 0:cb80564f40e1 164 * Indicates if a new packet can be sent
mluis 0:cb80564f40e1 165 */
mluis 0:cb80564f40e1 166 static bool NextTx = true;
mluis 0:cb80564f40e1 167
spcores 2:66f94cef0765 168 #if defined( SEMTECH_BC_APP )/*!
mluis 0:cb80564f40e1 169 * Hold the value returned from the Light Sensor
mluis 0:cb80564f40e1 170 */
spcores 1:c365eaf833bb 171 //static float LightValue = 0.0;
mluis 0:cb80564f40e1 172
mluis 0:cb80564f40e1 173 /*!
mluis 0:cb80564f40e1 174 * Control the 3-color LED
mluis 0:cb80564f40e1 175 * 0: automatic (LED goes brigther as the light decrease,
mluis 0:cb80564f40e1 176 * 1: manual (The LED is controlled by the user)
mluis 0:cb80564f40e1 177 */
mluis 0:cb80564f40e1 178 static uint8_t LightMode = 0; // 0:automatic, 1:manual
mluis 0:cb80564f40e1 179
mluis 0:cb80564f40e1 180 /*!
mluis 0:cb80564f40e1 181 * Ticker to create a PWM for the buzzer
mluis 0:cb80564f40e1 182 */
mluis 0:cb80564f40e1 183 Ticker BuzTimer;
mluis 0:cb80564f40e1 184
mluis 0:cb80564f40e1 185
mluis 0:cb80564f40e1 186 /*!
mluis 0:cb80564f40e1 187 * Constructor for Buzzer
mluis 0:cb80564f40e1 188 */
mluis 0:cb80564f40e1 189 DigitalOut buzzer(A3);
mluis 0:cb80564f40e1 190
mluis 0:cb80564f40e1 191 /*!
spcores 2:66f94cef0765 192 * Constructor for 4 Digit 7 semgent display
spcores 2:66f94cef0765 193 */
spcores 2:66f94cef0765 194 DigitDisplay display(D8, D9);
spcores 2:66f94cef0765 195
spcores 2:66f94cef0765 196 #endif
spcores 2:66f94cef0765 197
spcores 2:66f94cef0765 198 /*!
spcores 2:66f94cef0765 199 * Constructor for Light Sensor
spcores 2:66f94cef0765 200 */
spcores 2:66f94cef0765 201 AnalogIn LightSensor( A1 );
spcores 2:66f94cef0765 202
spcores 2:66f94cef0765 203 /**
spcores 2:66f94cef0765 204 Interrupt Event by SP
spcores 2:66f94cef0765 205 **/
spcores 2:66f94cef0765 206 InterruptIn buttonPressed(D8);
spcores 2:66f94cef0765 207
spcores 2:66f94cef0765 208 /*!
mluis 0:cb80564f40e1 209 * Constructor for the 3-color LED
mluis 0:cb80564f40e1 210 */
mluis 0:cb80564f40e1 211 #define NUM_LED 3
mluis 0:cb80564f40e1 212 ChainableLED color_led(D6, D7, NUM_LED);
mluis 0:cb80564f40e1 213
spcores 2:66f94cef0765 214 #define LIGHT_LEVEL 250 //0 : LED OFF | 250 : Bright White Light
mluis 0:cb80564f40e1 215
mluis 0:cb80564f40e1 216
spcores 1:c365eaf833bb 217 uint8_t buttonCount = 0;
spcores 1:c365eaf833bb 218 bool buttonStatus = false; //OFF = false & ON = true
spcores 1:c365eaf833bb 219 bool ledStatus = false; //OFF = false & ON = true
spcores 1:c365eaf833bb 220
spcores 1:c365eaf833bb 221 // Interrupt Handler for User Button
spcores 1:c365eaf833bb 222 void incButtonCount()
spcores 1:c365eaf833bb 223 {
spcores 1:c365eaf833bb 224 buttonCount++;
spcores 1:c365eaf833bb 225 buttonStatus=!buttonStatus;
spcores 1:c365eaf833bb 226 if (buttonStatus == 1)
spcores 1:c365eaf833bb 227 {
spcores 2:66f94cef0765 228 //Lights ON
spcores 1:c365eaf833bb 229 ledStatus=1;
spcores 2:66f94cef0765 230 color_led.setColorRGB(0, LIGHT_LEVEL, LIGHT_LEVEL, LIGHT_LEVEL);
spcores 2:66f94cef0765 231
spcores 1:c365eaf833bb 232 }
spcores 1:c365eaf833bb 233 else
spcores 1:c365eaf833bb 234 {
spcores 2:66f94cef0765 235 //Lights OFF
spcores 1:c365eaf833bb 236 ledStatus = 0;
spcores 2:66f94cef0765 237 color_led.setColorRGB(0, 0, 0, 0);
spcores 1:c365eaf833bb 238 }
spcores 1:c365eaf833bb 239 }
spcores 1:c365eaf833bb 240
mluis 0:cb80564f40e1 241 /*!
mluis 0:cb80564f40e1 242 * Device states
mluis 0:cb80564f40e1 243 */
mluis 0:cb80564f40e1 244 static enum eDevicState
mluis 0:cb80564f40e1 245 {
mluis 0:cb80564f40e1 246 DEVICE_STATE_INIT,
mluis 0:cb80564f40e1 247 DEVICE_STATE_JOIN,
mluis 0:cb80564f40e1 248 DEVICE_STATE_SEND,
mluis 0:cb80564f40e1 249 DEVICE_STATE_CYCLE,
mluis 0:cb80564f40e1 250 DEVICE_STATE_SLEEP
mluis 0:cb80564f40e1 251 }DeviceState;
mluis 0:cb80564f40e1 252
mluis 0:cb80564f40e1 253 /*!
mluis 0:cb80564f40e1 254 * LoRaWAN compliance tests support data
mluis 0:cb80564f40e1 255 */
mluis 0:cb80564f40e1 256 struct ComplianceTest_s
mluis 0:cb80564f40e1 257 {
mluis 0:cb80564f40e1 258 bool Running;
mluis 0:cb80564f40e1 259 uint8_t State;
mluis 0:cb80564f40e1 260 bool IsTxConfirmed;
mluis 0:cb80564f40e1 261 uint8_t AppPort;
mluis 0:cb80564f40e1 262 uint8_t AppDataSize;
mluis 0:cb80564f40e1 263 uint8_t *AppDataBuffer;
mluis 0:cb80564f40e1 264 uint16_t DownLinkCounter;
mluis 0:cb80564f40e1 265 bool LinkCheck;
mluis 0:cb80564f40e1 266 uint8_t DemodMargin;
mluis 0:cb80564f40e1 267 uint8_t NbGateways;
mluis 0:cb80564f40e1 268 }ComplianceTest;
mluis 0:cb80564f40e1 269
mluis 0:cb80564f40e1 270 /*
mluis 0:cb80564f40e1 271 * SerialDisplay managment variables
mluis 0:cb80564f40e1 272 */
mluis 0:cb80564f40e1 273
mluis 0:cb80564f40e1 274 /*!
mluis 0:cb80564f40e1 275 * Indicates if the MAC layer network join status has changed.
mluis 0:cb80564f40e1 276 */
mluis 0:cb80564f40e1 277 static bool IsNetworkJoinedStatusUpdate = false;
mluis 0:cb80564f40e1 278
mluis 0:cb80564f40e1 279 /*!
mluis 0:cb80564f40e1 280 * Strucure containing the Uplink status
mluis 0:cb80564f40e1 281 */
mluis 0:cb80564f40e1 282 struct sLoRaMacUplinkStatus
mluis 0:cb80564f40e1 283 {
mluis 0:cb80564f40e1 284 uint8_t Acked;
mluis 0:cb80564f40e1 285 int8_t Datarate;
mluis 0:cb80564f40e1 286 uint16_t UplinkCounter;
mluis 0:cb80564f40e1 287 uint8_t Port;
mluis 0:cb80564f40e1 288 uint8_t *Buffer;
mluis 0:cb80564f40e1 289 uint8_t BufferSize;
mluis 0:cb80564f40e1 290 }LoRaMacUplinkStatus;
mluis 0:cb80564f40e1 291 volatile bool UplinkStatusUpdated = false;
mluis 0:cb80564f40e1 292
mluis 0:cb80564f40e1 293 /*!
mluis 0:cb80564f40e1 294 * Strucure containing the Downlink status
mluis 0:cb80564f40e1 295 */
mluis 0:cb80564f40e1 296 struct sLoRaMacDownlinkStatus
mluis 0:cb80564f40e1 297 {
mluis 0:cb80564f40e1 298 int16_t Rssi;
mluis 0:cb80564f40e1 299 int8_t Snr;
mluis 0:cb80564f40e1 300 uint16_t DownlinkCounter;
mluis 0:cb80564f40e1 301 bool RxData;
mluis 0:cb80564f40e1 302 uint8_t Port;
mluis 0:cb80564f40e1 303 uint8_t *Buffer;
mluis 0:cb80564f40e1 304 uint8_t BufferSize;
mluis 0:cb80564f40e1 305 }LoRaMacDownlinkStatus;
mluis 0:cb80564f40e1 306 volatile bool DownlinkStatusUpdated = false;
mluis 0:cb80564f40e1 307
mluis 0:cb80564f40e1 308 void SerialDisplayRefresh( void )
mluis 0:cb80564f40e1 309 {
mluis 0:cb80564f40e1 310 MibRequestConfirm_t mibReq;
mluis 0:cb80564f40e1 311
mluis 0:cb80564f40e1 312 SerialDisplayInit( );
mluis 0:cb80564f40e1 313 SerialDisplayUpdateActivationMode( OVER_THE_AIR_ACTIVATION );
mluis 0:cb80564f40e1 314
mluis 0:cb80564f40e1 315 #if( OVER_THE_AIR_ACTIVATION == 0 )
mluis 0:cb80564f40e1 316 SerialDisplayUpdateNwkId( LORAWAN_NETWORK_ID );
mluis 0:cb80564f40e1 317 SerialDisplayUpdateDevAddr( DevAddr );
mluis 0:cb80564f40e1 318 SerialDisplayUpdateKey( 12, NwkSKey );
mluis 0:cb80564f40e1 319 SerialDisplayUpdateKey( 13, AppSKey );
mluis 0:cb80564f40e1 320 #else
mluis 0:cb80564f40e1 321 SerialDisplayUpdateEui( 5, DevEui );
mluis 0:cb80564f40e1 322 SerialDisplayUpdateEui( 6, AppEui );
mluis 0:cb80564f40e1 323 SerialDisplayUpdateKey( 7, AppKey );
mluis 0:cb80564f40e1 324 #endif
mluis 0:cb80564f40e1 325
mluis 0:cb80564f40e1 326 mibReq.Type = MIB_NETWORK_JOINED;
mluis 0:cb80564f40e1 327 LoRaMacMibGetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 328 SerialDisplayUpdateNetworkIsJoined( mibReq.Param.IsNetworkJoined );
mluis 0:cb80564f40e1 329
mluis 0:cb80564f40e1 330 SerialDisplayUpdateAdr( LORAWAN_ADR_ON );
spcores 1:c365eaf833bb 331 #if defined( USE_BAND_868 ) || defined ( USE_BAND_865 )
mluis 0:cb80564f40e1 332 SerialDisplayUpdateDutyCycle( LORAWAN_DUTYCYCLE_ON );
mluis 0:cb80564f40e1 333 #else
mluis 0:cb80564f40e1 334 SerialDisplayUpdateDutyCycle( false );
mluis 0:cb80564f40e1 335 #endif
mluis 0:cb80564f40e1 336 SerialDisplayUpdatePublicNetwork( LORAWAN_PUBLIC_NETWORK );
mluis 0:cb80564f40e1 337
mluis 0:cb80564f40e1 338 SerialDisplayUpdateLedState( 3, AppLedStateOn );
mluis 0:cb80564f40e1 339 }
mluis 0:cb80564f40e1 340
mluis 0:cb80564f40e1 341 void SerialRxProcess( void )
mluis 0:cb80564f40e1 342 {
mluis 0:cb80564f40e1 343 if( SerialDisplayReadable( ) == true )
mluis 0:cb80564f40e1 344 {
mluis 0:cb80564f40e1 345 switch( SerialDisplayGetChar( ) )
mluis 0:cb80564f40e1 346 {
mluis 0:cb80564f40e1 347 case 'R':
mluis 0:cb80564f40e1 348 case 'r':
mluis 0:cb80564f40e1 349 // Refresh Serial screen
mluis 0:cb80564f40e1 350 SerialDisplayRefresh( );
mluis 0:cb80564f40e1 351 break;
mluis 0:cb80564f40e1 352 default:
mluis 0:cb80564f40e1 353 break;
mluis 0:cb80564f40e1 354 }
mluis 0:cb80564f40e1 355 }
mluis 0:cb80564f40e1 356 }
mluis 0:cb80564f40e1 357
mluis 0:cb80564f40e1 358 /*!
mluis 0:cb80564f40e1 359 * \brief Prepares the payload of the frame
mluis 0:cb80564f40e1 360 */
mluis 0:cb80564f40e1 361 static void PrepareTxFrame( uint8_t port )
mluis 0:cb80564f40e1 362 {
mluis 0:cb80564f40e1 363 uint32_t tempValue;
mluis 0:cb80564f40e1 364
mluis 0:cb80564f40e1 365 switch( port )
mluis 0:cb80564f40e1 366 {
spcores 1:c365eaf833bb 367 case 5:
spcores 1:c365eaf833bb 368 tempValue = LightSensor.read_u16();
spcores 1:c365eaf833bb 369 AppData[0] = (( tempValue & 0xFF00 ) >> 8 ) & 0xFF;
spcores 1:c365eaf833bb 370 AppData[1] = ( tempValue & 0x00FF );
spcores 1:c365eaf833bb 371 AppData[2] = 44; // Sending ','
spcores 1:c365eaf833bb 372 AppData[3] = ledStatus + 48; //Send LED status ON/OFF
spcores 1:c365eaf833bb 373
spcores 1:c365eaf833bb 374 //printf("Light Sensor = %d , %x", tempValue, tempValue);
spcores 1:c365eaf833bb 375 break;
spcores 1:c365eaf833bb 376
mluis 0:cb80564f40e1 377 case 10:
mluis 0:cb80564f40e1 378 {
spcores 1:c365eaf833bb 379 AppData[0] = 72;
spcores 1:c365eaf833bb 380 AppData[1] = 69;
spcores 1:c365eaf833bb 381 AppData[2] = 76;
spcores 1:c365eaf833bb 382 AppData[3] = 76;
spcores 1:c365eaf833bb 383 AppData[4] = 79;
spcores 1:c365eaf833bb 384
spcores 1:c365eaf833bb 385 tempValue = buttonStatus + 48;
spcores 1:c365eaf833bb 386 AppData[5] = tempValue;
spcores 1:c365eaf833bb 387
spcores 1:c365eaf833bb 388 buttonCount = 0;
spcores 1:c365eaf833bb 389 /*
mluis 0:cb80564f40e1 390 tempValue = ( uint32_t )( LightValue * 1000000.0 );
mluis 0:cb80564f40e1 391 AppData[0] = LightMode;
mluis 0:cb80564f40e1 392 AppData[1] = ( ( tempValue & 0xFF000000 ) >> 24 ) & 0xFF;
mluis 0:cb80564f40e1 393 AppData[2] = ( ( tempValue & 0x00FF0000 ) >> 16 ) & 0xFF;
mluis 0:cb80564f40e1 394 AppData[3] = ( ( tempValue & 0x0000FF00 ) >> 8 ) & 0xFF;
mluis 0:cb80564f40e1 395 AppData[4] = ( tempValue & 0x000000FF );
spcores 1:c365eaf833bb 396 */
mluis 0:cb80564f40e1 397 }
mluis 0:cb80564f40e1 398 break;
mluis 0:cb80564f40e1 399 case 15:
mluis 0:cb80564f40e1 400 {
mluis 0:cb80564f40e1 401 AppData[0] = AppLedStateOn;
mluis 0:cb80564f40e1 402 if( IsTxConfirmed == true )
mluis 0:cb80564f40e1 403 {
mluis 0:cb80564f40e1 404 AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
mluis 0:cb80564f40e1 405 AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter;
mluis 0:cb80564f40e1 406 AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8;
mluis 0:cb80564f40e1 407 AppData[4] = LoRaMacDownlinkStatus.Rssi;
mluis 0:cb80564f40e1 408 AppData[5] = LoRaMacDownlinkStatus.Snr;
mluis 0:cb80564f40e1 409 }
mluis 0:cb80564f40e1 410 }
mluis 0:cb80564f40e1 411 break;
mluis 0:cb80564f40e1 412 case 224:
mluis 0:cb80564f40e1 413 if( ComplianceTest.LinkCheck == true )
mluis 0:cb80564f40e1 414 {
mluis 0:cb80564f40e1 415 ComplianceTest.LinkCheck = false;
mluis 0:cb80564f40e1 416 AppDataSize = 3;
mluis 0:cb80564f40e1 417 AppData[0] = 5;
mluis 0:cb80564f40e1 418 AppData[1] = ComplianceTest.DemodMargin;
mluis 0:cb80564f40e1 419 AppData[2] = ComplianceTest.NbGateways;
mluis 0:cb80564f40e1 420 ComplianceTest.State = 1;
mluis 0:cb80564f40e1 421 }
mluis 0:cb80564f40e1 422 else
mluis 0:cb80564f40e1 423 {
mluis 0:cb80564f40e1 424 switch( ComplianceTest.State )
mluis 0:cb80564f40e1 425 {
mluis 0:cb80564f40e1 426 case 4:
mluis 0:cb80564f40e1 427 ComplianceTest.State = 1;
mluis 0:cb80564f40e1 428 break;
mluis 0:cb80564f40e1 429 case 1:
mluis 0:cb80564f40e1 430 AppDataSize = 2;
mluis 0:cb80564f40e1 431 AppData[0] = ComplianceTest.DownLinkCounter >> 8;
mluis 0:cb80564f40e1 432 AppData[1] = ComplianceTest.DownLinkCounter;
mluis 0:cb80564f40e1 433 break;
mluis 0:cb80564f40e1 434 }
mluis 0:cb80564f40e1 435 }
mluis 0:cb80564f40e1 436 break;
mluis 0:cb80564f40e1 437 default:
mluis 0:cb80564f40e1 438 break;
mluis 0:cb80564f40e1 439 }
mluis 0:cb80564f40e1 440 }
mluis 0:cb80564f40e1 441
mluis 0:cb80564f40e1 442 /*!
mluis 0:cb80564f40e1 443 * \brief Prepares the payload of the frame
mluis 0:cb80564f40e1 444 *
mluis 0:cb80564f40e1 445 * \retval [0: frame could be send, 1: error]
mluis 0:cb80564f40e1 446 */
mluis 0:cb80564f40e1 447 static bool SendFrame( void )
mluis 0:cb80564f40e1 448 {
mluis 0:cb80564f40e1 449 McpsReq_t mcpsReq;
mluis 0:cb80564f40e1 450 LoRaMacTxInfo_t txInfo;
mluis 0:cb80564f40e1 451
mluis 0:cb80564f40e1 452 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
mluis 0:cb80564f40e1 453 {
mluis 0:cb80564f40e1 454 // Send empty frame in order to flush MAC commands
mluis 0:cb80564f40e1 455 mcpsReq.Type = MCPS_UNCONFIRMED;
mluis 0:cb80564f40e1 456 mcpsReq.Req.Unconfirmed.fBuffer = NULL;
mluis 0:cb80564f40e1 457 mcpsReq.Req.Unconfirmed.fBufferSize = 0;
mluis 0:cb80564f40e1 458 mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
mluis 0:cb80564f40e1 459
mluis 0:cb80564f40e1 460 LoRaMacUplinkStatus.Acked = false;
mluis 0:cb80564f40e1 461 LoRaMacUplinkStatus.Port = 0;
mluis 0:cb80564f40e1 462 LoRaMacUplinkStatus.Buffer = NULL;
mluis 0:cb80564f40e1 463 LoRaMacUplinkStatus.BufferSize = 0;
mluis 0:cb80564f40e1 464 SerialDisplayUpdateFrameType( false );
mluis 0:cb80564f40e1 465 }
mluis 0:cb80564f40e1 466 else
mluis 0:cb80564f40e1 467 {
mluis 0:cb80564f40e1 468 LoRaMacUplinkStatus.Acked = false;
mluis 0:cb80564f40e1 469 LoRaMacUplinkStatus.Port = AppPort;
mluis 0:cb80564f40e1 470 LoRaMacUplinkStatus.Buffer = AppData;
mluis 0:cb80564f40e1 471 LoRaMacUplinkStatus.BufferSize = AppDataSize;
mluis 0:cb80564f40e1 472 SerialDisplayUpdateFrameType( IsTxConfirmed );
mluis 0:cb80564f40e1 473
mluis 0:cb80564f40e1 474 if( IsTxConfirmed == false )
mluis 0:cb80564f40e1 475 {
mluis 0:cb80564f40e1 476 mcpsReq.Type = MCPS_UNCONFIRMED;
mluis 0:cb80564f40e1 477 mcpsReq.Req.Unconfirmed.fPort = AppPort;
mluis 0:cb80564f40e1 478 mcpsReq.Req.Unconfirmed.fBuffer = AppData;
mluis 0:cb80564f40e1 479 mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
mluis 0:cb80564f40e1 480 mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
mluis 0:cb80564f40e1 481 }
mluis 0:cb80564f40e1 482 else
mluis 0:cb80564f40e1 483 {
mluis 0:cb80564f40e1 484 mcpsReq.Type = MCPS_CONFIRMED;
mluis 0:cb80564f40e1 485 mcpsReq.Req.Confirmed.fPort = AppPort;
mluis 0:cb80564f40e1 486 mcpsReq.Req.Confirmed.fBuffer = AppData;
mluis 0:cb80564f40e1 487 mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
mluis 0:cb80564f40e1 488 mcpsReq.Req.Confirmed.NbTrials = 8;
mluis 0:cb80564f40e1 489 mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
mluis 0:cb80564f40e1 490 }
mluis 0:cb80564f40e1 491 }
mluis 0:cb80564f40e1 492
mluis 0:cb80564f40e1 493 if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
mluis 0:cb80564f40e1 494 {
mluis 0:cb80564f40e1 495 return false;
mluis 0:cb80564f40e1 496 }
mluis 0:cb80564f40e1 497 return true;
mluis 0:cb80564f40e1 498 }
mluis 0:cb80564f40e1 499
mluis 0:cb80564f40e1 500 /*!
mluis 0:cb80564f40e1 501 * \brief Function executed on TxNextPacket Timeout event
mluis 0:cb80564f40e1 502 */
mluis 0:cb80564f40e1 503 static void OnTxNextPacketTimerEvent( void )
mluis 0:cb80564f40e1 504 {
mluis 0:cb80564f40e1 505 MibRequestConfirm_t mibReq;
mluis 0:cb80564f40e1 506 LoRaMacStatus_t status;
mluis 0:cb80564f40e1 507
mluis 0:cb80564f40e1 508 TimerStop( &TxNextPacketTimer );
mluis 0:cb80564f40e1 509
mluis 0:cb80564f40e1 510 mibReq.Type = MIB_NETWORK_JOINED;
mluis 0:cb80564f40e1 511 status = LoRaMacMibGetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 512
mluis 0:cb80564f40e1 513 if( status == LORAMAC_STATUS_OK )
mluis 0:cb80564f40e1 514 {
mluis 0:cb80564f40e1 515 if( mibReq.Param.IsNetworkJoined == true )
mluis 0:cb80564f40e1 516 {
mluis 0:cb80564f40e1 517 DeviceState = DEVICE_STATE_SEND;
mluis 0:cb80564f40e1 518 NextTx = true;
mluis 0:cb80564f40e1 519 }
mluis 0:cb80564f40e1 520 else
mluis 0:cb80564f40e1 521 {
mluis 0:cb80564f40e1 522 DeviceState = DEVICE_STATE_JOIN;
mluis 0:cb80564f40e1 523 }
mluis 0:cb80564f40e1 524 }
mluis 0:cb80564f40e1 525 }
mluis 0:cb80564f40e1 526
mluis 0:cb80564f40e1 527 /*!
mluis 0:cb80564f40e1 528 * \brief Function executed on Led 1 Timeout event
mluis 0:cb80564f40e1 529 */
mluis 0:cb80564f40e1 530 static void OnLed1TimerEvent( void )
mluis 0:cb80564f40e1 531 {
mluis 0:cb80564f40e1 532 TimerStop( &Led1Timer );
mluis 0:cb80564f40e1 533 // Switch LED 1 OFF
mluis 0:cb80564f40e1 534 Led1State = false;
mluis 0:cb80564f40e1 535 Led1StateChanged = true;
mluis 0:cb80564f40e1 536 }
mluis 0:cb80564f40e1 537
mluis 0:cb80564f40e1 538 /*!
mluis 0:cb80564f40e1 539 * \brief Function executed on Led 2 Timeout event
mluis 0:cb80564f40e1 540 */
mluis 0:cb80564f40e1 541 static void OnLed2TimerEvent( void )
mluis 0:cb80564f40e1 542 {
mluis 0:cb80564f40e1 543 TimerStop( &Led2Timer );
mluis 0:cb80564f40e1 544 // Switch LED 2 OFF
mluis 0:cb80564f40e1 545 Led2State = false;
mluis 0:cb80564f40e1 546 Led2StateChanged = true;
mluis 0:cb80564f40e1 547 }
mluis 0:cb80564f40e1 548
spcores 2:66f94cef0765 549 #if defined( SEMTECH_BC_APP )
mluis 0:cb80564f40e1 550 /*!
mluis 0:cb80564f40e1 551 * \brief Function executed on Buzzer Timeout event
mluis 0:cb80564f40e1 552 */
mluis 0:cb80564f40e1 553 static void OnBuzTimerEvent( void )
mluis 0:cb80564f40e1 554 {
mluis 0:cb80564f40e1 555 buzzer = 0;
mluis 0:cb80564f40e1 556 BuzTimer.detach( );
mluis 0:cb80564f40e1 557 }
spcores 2:66f94cef0765 558 #endif
mluis 0:cb80564f40e1 559 /*!
mluis 0:cb80564f40e1 560 * \brief MCPS-Confirm event function
mluis 0:cb80564f40e1 561 *
mluis 0:cb80564f40e1 562 * \param [IN] McpsConfirm - Pointer to the confirm structure,
mluis 0:cb80564f40e1 563 * containing confirm attributes.
mluis 0:cb80564f40e1 564 */
mluis 0:cb80564f40e1 565 static void McpsConfirm( McpsConfirm_t *McpsConfirm )
mluis 0:cb80564f40e1 566 {
mluis 0:cb80564f40e1 567 if( McpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
mluis 0:cb80564f40e1 568 {
mluis 0:cb80564f40e1 569 switch( McpsConfirm->McpsRequest )
mluis 0:cb80564f40e1 570 {
mluis 0:cb80564f40e1 571 case MCPS_UNCONFIRMED:
mluis 0:cb80564f40e1 572 {
mluis 0:cb80564f40e1 573 // Check Datarate
mluis 0:cb80564f40e1 574 // Check TxPower
mluis 0:cb80564f40e1 575 break;
mluis 0:cb80564f40e1 576 }
mluis 0:cb80564f40e1 577 case MCPS_CONFIRMED:
mluis 0:cb80564f40e1 578 {
mluis 0:cb80564f40e1 579 // Check Datarate
mluis 0:cb80564f40e1 580 // Check TxPower
mluis 0:cb80564f40e1 581 // Check AckReceived
mluis 0:cb80564f40e1 582 // Check NbRetries
mluis 0:cb80564f40e1 583 LoRaMacUplinkStatus.Acked = McpsConfirm->AckReceived;
mluis 0:cb80564f40e1 584 break;
mluis 0:cb80564f40e1 585 }
mluis 0:cb80564f40e1 586 case MCPS_PROPRIETARY:
mluis 0:cb80564f40e1 587 {
mluis 0:cb80564f40e1 588 break;
mluis 0:cb80564f40e1 589 }
mluis 0:cb80564f40e1 590 default:
mluis 0:cb80564f40e1 591 break;
mluis 0:cb80564f40e1 592 }
mluis 0:cb80564f40e1 593 LoRaMacUplinkStatus.Datarate = McpsConfirm->Datarate;
mluis 0:cb80564f40e1 594 LoRaMacUplinkStatus.UplinkCounter = McpsConfirm->UpLinkCounter;
mluis 0:cb80564f40e1 595
mluis 0:cb80564f40e1 596 UplinkStatusUpdated = true;
mluis 0:cb80564f40e1 597 }
mluis 0:cb80564f40e1 598 NextTx = true;
mluis 0:cb80564f40e1 599 }
mluis 0:cb80564f40e1 600
mluis 0:cb80564f40e1 601 /*!
mluis 0:cb80564f40e1 602 * \brief MCPS-Indication event function
mluis 0:cb80564f40e1 603 *
mluis 0:cb80564f40e1 604 * \param [IN] McpsIndication - Pointer to the indication structure,
mluis 0:cb80564f40e1 605 * containing indication attributes.
mluis 0:cb80564f40e1 606 */
mluis 0:cb80564f40e1 607 static void McpsIndication( McpsIndication_t *McpsIndication )
mluis 0:cb80564f40e1 608 {
mluis 0:cb80564f40e1 609 if( McpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
mluis 0:cb80564f40e1 610 {
mluis 0:cb80564f40e1 611 return;
mluis 0:cb80564f40e1 612 }
mluis 0:cb80564f40e1 613
mluis 0:cb80564f40e1 614 switch( McpsIndication->McpsIndication )
mluis 0:cb80564f40e1 615 {
mluis 0:cb80564f40e1 616 case MCPS_UNCONFIRMED:
mluis 0:cb80564f40e1 617 {
mluis 0:cb80564f40e1 618 break;
mluis 0:cb80564f40e1 619 }
mluis 0:cb80564f40e1 620 case MCPS_CONFIRMED:
mluis 0:cb80564f40e1 621 {
mluis 0:cb80564f40e1 622 break;
mluis 0:cb80564f40e1 623 }
mluis 0:cb80564f40e1 624 case MCPS_PROPRIETARY:
mluis 0:cb80564f40e1 625 {
mluis 0:cb80564f40e1 626 break;
mluis 0:cb80564f40e1 627 }
mluis 0:cb80564f40e1 628 case MCPS_MULTICAST:
mluis 0:cb80564f40e1 629 {
mluis 0:cb80564f40e1 630 break;
mluis 0:cb80564f40e1 631 }
mluis 0:cb80564f40e1 632 default:
mluis 0:cb80564f40e1 633 break;
mluis 0:cb80564f40e1 634 }
mluis 0:cb80564f40e1 635
mluis 0:cb80564f40e1 636 // Check Multicast
mluis 0:cb80564f40e1 637 // Check Port
mluis 0:cb80564f40e1 638 // Check Datarate
mluis 0:cb80564f40e1 639 // Check FramePending
mluis 0:cb80564f40e1 640 // Check Buffer
mluis 0:cb80564f40e1 641 // Check BufferSize
mluis 0:cb80564f40e1 642 // Check Rssi
mluis 0:cb80564f40e1 643 // Check Snr
mluis 0:cb80564f40e1 644 // Check RxSlot
mluis 0:cb80564f40e1 645 LoRaMacDownlinkStatus.Rssi = McpsIndication->Rssi;
mluis 0:cb80564f40e1 646 if( McpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
mluis 0:cb80564f40e1 647 {
mluis 0:cb80564f40e1 648 // Invert and divide by 4
mluis 0:cb80564f40e1 649 LoRaMacDownlinkStatus.Snr = ( ( ~McpsIndication->Snr + 1 ) & 0xFF ) >> 2;
mluis 0:cb80564f40e1 650 LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
mluis 0:cb80564f40e1 651 }
mluis 0:cb80564f40e1 652 else
mluis 0:cb80564f40e1 653 {
mluis 0:cb80564f40e1 654 // Divide by 4
mluis 0:cb80564f40e1 655 LoRaMacDownlinkStatus.Snr = ( McpsIndication->Snr & 0xFF ) >> 2;
mluis 0:cb80564f40e1 656 }
mluis 0:cb80564f40e1 657 LoRaMacDownlinkStatus.DownlinkCounter++;
mluis 0:cb80564f40e1 658 LoRaMacDownlinkStatus.RxData = McpsIndication->RxData;
mluis 0:cb80564f40e1 659 LoRaMacDownlinkStatus.Port = McpsIndication->Port;
mluis 0:cb80564f40e1 660 LoRaMacDownlinkStatus.Buffer = McpsIndication->Buffer;
mluis 0:cb80564f40e1 661 LoRaMacDownlinkStatus.BufferSize = McpsIndication->BufferSize;
mluis 0:cb80564f40e1 662
mluis 0:cb80564f40e1 663 if( ComplianceTest.Running == true )
mluis 0:cb80564f40e1 664 {
mluis 0:cb80564f40e1 665 ComplianceTest.DownLinkCounter++;
mluis 0:cb80564f40e1 666 }
mluis 0:cb80564f40e1 667
mluis 0:cb80564f40e1 668 if( McpsIndication->RxData == true )
mluis 0:cb80564f40e1 669 {
mluis 0:cb80564f40e1 670 switch( McpsIndication->Port )
mluis 0:cb80564f40e1 671 {
mluis 0:cb80564f40e1 672 case 1: // The application LED can be controlled on port 1 or 2
mluis 0:cb80564f40e1 673 case 2:
mluis 0:cb80564f40e1 674 if( McpsIndication->BufferSize == 1 )
mluis 0:cb80564f40e1 675 {
mluis 0:cb80564f40e1 676 AppLedStateOn = McpsIndication->Buffer[0] & 0x01;
mluis 0:cb80564f40e1 677 Led3StateChanged = true;
mluis 0:cb80564f40e1 678 }
mluis 0:cb80564f40e1 679 break;
spcores 2:66f94cef0765 680 case 5:
spcores 2:66f94cef0765 681 //printf("****************************Msg Received from Server ********************");
spcores 2:66f94cef0765 682 break;
mluis 0:cb80564f40e1 683 case 10:
spcores 2:66f94cef0765 684 /*
spcores 2:66f94cef0765 685 display.write( 0, McpsIndication->Buffer[0] );
spcores 2:66f94cef0765 686 display.write( 1, McpsIndication->Buffer[1] );
spcores 2:66f94cef0765 687 display.write( 2, McpsIndication->Buffer[2] );
spcores 2:66f94cef0765 688 display.write( 3, McpsIndication->Buffer[3] );
spcores 2:66f94cef0765 689 */
spcores 2:66f94cef0765 690 buttonStatus=McpsIndication->Buffer[0];
spcores 2:66f94cef0765 691
spcores 2:66f94cef0765 692 if (buttonStatus == 1)
spcores 2:66f94cef0765 693 {
spcores 2:66f94cef0765 694 //Lights ON
spcores 2:66f94cef0765 695 ledStatus=1;
spcores 2:66f94cef0765 696 color_led.setColorRGB(0, LIGHT_LEVEL, LIGHT_LEVEL, LIGHT_LEVEL);
spcores 2:66f94cef0765 697
spcores 2:66f94cef0765 698 }
spcores 2:66f94cef0765 699 else
spcores 2:66f94cef0765 700 {
spcores 2:66f94cef0765 701 //Lights OFF
spcores 2:66f94cef0765 702 ledStatus = 0;
spcores 2:66f94cef0765 703 color_led.setColorRGB(0, 0, 0, 0);
spcores 2:66f94cef0765 704 }
mluis 0:cb80564f40e1 705 break;
mluis 0:cb80564f40e1 706
spcores 2:66f94cef0765 707 #if defined( SEMTECH_BC_APP )
mluis 0:cb80564f40e1 708 case 20:
mluis 0:cb80564f40e1 709 LightMode = McpsIndication->Buffer[0];
mluis 0:cb80564f40e1 710 if( LightMode )
mluis 0:cb80564f40e1 711 {
mluis 0:cb80564f40e1 712 color_led.setColorRGB(0, McpsIndication->Buffer[1], McpsIndication->Buffer[2], McpsIndication->Buffer[3] );
mluis 0:cb80564f40e1 713 }
mluis 0:cb80564f40e1 714 break;
mluis 0:cb80564f40e1 715
mluis 0:cb80564f40e1 716 case 30:
mluis 0:cb80564f40e1 717 BuzTimer.attach_us( &OnBuzTimerEvent, 200000 );
mluis 0:cb80564f40e1 718 buzzer = 1;
mluis 0:cb80564f40e1 719 break;
spcores 2:66f94cef0765 720 #endif
mluis 0:cb80564f40e1 721 case 224:
mluis 0:cb80564f40e1 722 if( ComplianceTest.Running == false )
mluis 0:cb80564f40e1 723 {
mluis 0:cb80564f40e1 724 // Check compliance test enable command (i)
mluis 0:cb80564f40e1 725 if( ( McpsIndication->BufferSize == 4 ) &&
mluis 0:cb80564f40e1 726 ( McpsIndication->Buffer[0] == 0x01 ) &&
mluis 0:cb80564f40e1 727 ( McpsIndication->Buffer[1] == 0x01 ) &&
mluis 0:cb80564f40e1 728 ( McpsIndication->Buffer[2] == 0x01 ) &&
mluis 0:cb80564f40e1 729 ( McpsIndication->Buffer[3] == 0x01 ) )
mluis 0:cb80564f40e1 730 {
mluis 0:cb80564f40e1 731 IsTxConfirmed = false;
mluis 0:cb80564f40e1 732 AppPort = 224;
mluis 0:cb80564f40e1 733 AppDataSize = 2;
mluis 0:cb80564f40e1 734 ComplianceTest.DownLinkCounter = 0;
mluis 0:cb80564f40e1 735 ComplianceTest.LinkCheck = false;
mluis 0:cb80564f40e1 736 ComplianceTest.DemodMargin = 0;
mluis 0:cb80564f40e1 737 ComplianceTest.NbGateways = 0;
mluis 0:cb80564f40e1 738 ComplianceTest.Running = true;
mluis 0:cb80564f40e1 739 ComplianceTest.State = 1;
mluis 0:cb80564f40e1 740
mluis 0:cb80564f40e1 741 MibRequestConfirm_t mibReq;
mluis 0:cb80564f40e1 742 mibReq.Type = MIB_ADR;
mluis 0:cb80564f40e1 743 mibReq.Param.AdrEnable = true;
mluis 0:cb80564f40e1 744 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 745
spcores 1:c365eaf833bb 746 #if defined( USE_BAND_868 ) || defined( USE_BAND_865 )
mluis 0:cb80564f40e1 747 LoRaMacTestSetDutyCycleOn( false );
mluis 0:cb80564f40e1 748 #endif
mluis 0:cb80564f40e1 749 }
mluis 0:cb80564f40e1 750 }
mluis 0:cb80564f40e1 751 else
mluis 0:cb80564f40e1 752 {
mluis 0:cb80564f40e1 753 ComplianceTest.State = McpsIndication->Buffer[0];
mluis 0:cb80564f40e1 754 switch( ComplianceTest.State )
mluis 0:cb80564f40e1 755 {
mluis 0:cb80564f40e1 756 case 0: // Check compliance test disable command (ii)
mluis 0:cb80564f40e1 757 IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
mluis 0:cb80564f40e1 758 AppPort = LORAWAN_APP_PORT;
mluis 0:cb80564f40e1 759 AppDataSize = LORAWAN_APP_DATA_SIZE;
mluis 0:cb80564f40e1 760 ComplianceTest.DownLinkCounter = 0;
mluis 0:cb80564f40e1 761 ComplianceTest.Running = false;
mluis 0:cb80564f40e1 762
mluis 0:cb80564f40e1 763 MibRequestConfirm_t mibReq;
mluis 0:cb80564f40e1 764 mibReq.Type = MIB_ADR;
mluis 0:cb80564f40e1 765 mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
mluis 0:cb80564f40e1 766 LoRaMacMibSetRequestConfirm( &mibReq );
spcores 1:c365eaf833bb 767 #if defined( USE_BAND_868 ) || defined( USE_BAND_865 )
mluis 0:cb80564f40e1 768 LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
mluis 0:cb80564f40e1 769 #endif
mluis 0:cb80564f40e1 770 break;
mluis 0:cb80564f40e1 771 case 1: // (iii, iv)
mluis 0:cb80564f40e1 772 AppDataSize = 2;
mluis 0:cb80564f40e1 773 break;
mluis 0:cb80564f40e1 774 case 2: // Enable confirmed messages (v)
mluis 0:cb80564f40e1 775 IsTxConfirmed = true;
mluis 0:cb80564f40e1 776 ComplianceTest.State = 1;
mluis 0:cb80564f40e1 777 break;
mluis 0:cb80564f40e1 778 case 3: // Disable confirmed messages (vi)
mluis 0:cb80564f40e1 779 IsTxConfirmed = false;
mluis 0:cb80564f40e1 780 ComplianceTest.State = 1;
mluis 0:cb80564f40e1 781 break;
mluis 0:cb80564f40e1 782 case 4: // (vii)
mluis 0:cb80564f40e1 783 AppDataSize = McpsIndication->BufferSize;
mluis 0:cb80564f40e1 784
mluis 0:cb80564f40e1 785 AppData[0] = 4;
mluis 0:cb80564f40e1 786 for( uint8_t i = 1; i < AppDataSize; i++ )
mluis 0:cb80564f40e1 787 {
mluis 0:cb80564f40e1 788 AppData[i] = McpsIndication->Buffer[i] + 1;
mluis 0:cb80564f40e1 789 }
mluis 0:cb80564f40e1 790 break;
mluis 0:cb80564f40e1 791 case 5: // (viii)
mluis 0:cb80564f40e1 792 {
mluis 0:cb80564f40e1 793 MlmeReq_t mlmeReq;
mluis 0:cb80564f40e1 794 mlmeReq.Type = MLME_LINK_CHECK;
mluis 0:cb80564f40e1 795 LoRaMacMlmeRequest( &mlmeReq );
mluis 0:cb80564f40e1 796 }
mluis 0:cb80564f40e1 797 break;
mluis 0:cb80564f40e1 798 default:
mluis 0:cb80564f40e1 799 break;
mluis 0:cb80564f40e1 800 }
mluis 0:cb80564f40e1 801 }
mluis 0:cb80564f40e1 802 break;
mluis 0:cb80564f40e1 803 default:
mluis 0:cb80564f40e1 804 break;
mluis 0:cb80564f40e1 805 }
mluis 0:cb80564f40e1 806 }
mluis 0:cb80564f40e1 807
mluis 0:cb80564f40e1 808 // Switch LED 2 ON for each received downlink
mluis 0:cb80564f40e1 809 Led2State = true;
mluis 0:cb80564f40e1 810 Led2StateChanged = true;
mluis 0:cb80564f40e1 811 TimerStart( &Led2Timer );
mluis 0:cb80564f40e1 812 DownlinkStatusUpdated = true;
mluis 0:cb80564f40e1 813 }
mluis 0:cb80564f40e1 814
mluis 0:cb80564f40e1 815 /*!
mluis 0:cb80564f40e1 816 * \brief MLME-Confirm event function
mluis 0:cb80564f40e1 817 *
mluis 0:cb80564f40e1 818 * \param [IN] MlmeConfirm - Pointer to the confirm structure,
mluis 0:cb80564f40e1 819 * containing confirm attributes.
mluis 0:cb80564f40e1 820 */
mluis 0:cb80564f40e1 821 static void MlmeConfirm( MlmeConfirm_t *MlmeConfirm )
mluis 0:cb80564f40e1 822 {
mluis 0:cb80564f40e1 823 if( MlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
mluis 0:cb80564f40e1 824 {
mluis 0:cb80564f40e1 825 switch( MlmeConfirm->MlmeRequest )
mluis 0:cb80564f40e1 826 {
mluis 0:cb80564f40e1 827 case MLME_JOIN:
mluis 0:cb80564f40e1 828 {
mluis 0:cb80564f40e1 829 // Status is OK, node has joined the network
mluis 0:cb80564f40e1 830 IsNetworkJoinedStatusUpdate = true;
mluis 0:cb80564f40e1 831 break;
mluis 0:cb80564f40e1 832 }
mluis 0:cb80564f40e1 833 case MLME_LINK_CHECK:
mluis 0:cb80564f40e1 834 {
mluis 0:cb80564f40e1 835 // Check DemodMargin
mluis 0:cb80564f40e1 836 // Check NbGateways
mluis 0:cb80564f40e1 837 if( ComplianceTest.Running == true )
mluis 0:cb80564f40e1 838 {
mluis 0:cb80564f40e1 839 ComplianceTest.LinkCheck = true;
mluis 0:cb80564f40e1 840 ComplianceTest.DemodMargin = MlmeConfirm->DemodMargin;
mluis 0:cb80564f40e1 841 ComplianceTest.NbGateways = MlmeConfirm->NbGateways;
mluis 0:cb80564f40e1 842 }
mluis 0:cb80564f40e1 843 break;
mluis 0:cb80564f40e1 844 }
mluis 0:cb80564f40e1 845 default:
mluis 0:cb80564f40e1 846 break;
mluis 0:cb80564f40e1 847 }
mluis 0:cb80564f40e1 848 }
mluis 0:cb80564f40e1 849 NextTx = true;
mluis 0:cb80564f40e1 850 UplinkStatusUpdated = true;
mluis 0:cb80564f40e1 851 }
mluis 0:cb80564f40e1 852
mluis 0:cb80564f40e1 853 /**
mluis 0:cb80564f40e1 854 * Main application entry point.
mluis 0:cb80564f40e1 855 */
mluis 0:cb80564f40e1 856 int main( void )
mluis 0:cb80564f40e1 857 {
spcores 1:c365eaf833bb 858 //float tempLightValue = 0.0;
spcores 2:66f94cef0765 859 #if defined( SEMTECH_BC_APP )
mluis 0:cb80564f40e1 860 LightMode = 0; // 0: manual, 1: automatic
mluis 0:cb80564f40e1 861 buzzer = 0; // 0: OFF, 1: ON
spcores 2:66f94cef0765 862 #endif
spcores 2:66f94cef0765 863
mluis 0:cb80564f40e1 864
mluis 0:cb80564f40e1 865 LoRaMacPrimitives_t LoRaMacPrimitives;
mluis 0:cb80564f40e1 866 LoRaMacCallback_t LoRaMacCallbacks;
mluis 0:cb80564f40e1 867 MibRequestConfirm_t mibReq;
mluis 0:cb80564f40e1 868
mluis 0:cb80564f40e1 869 BoardInit( );
mluis 0:cb80564f40e1 870 SerialDisplayInit( );
spcores 1:c365eaf833bb 871 buttonPressed.rise(&incButtonCount);
spcores 1:c365eaf833bb 872
mluis 0:cb80564f40e1 873 DeviceState = DEVICE_STATE_INIT;
mluis 0:cb80564f40e1 874
mluis 0:cb80564f40e1 875 while( 1 )
mluis 0:cb80564f40e1 876 {
mluis 0:cb80564f40e1 877 SerialRxProcess( );
mluis 0:cb80564f40e1 878 if( IsNetworkJoinedStatusUpdate == true )
mluis 0:cb80564f40e1 879 {
mluis 0:cb80564f40e1 880 IsNetworkJoinedStatusUpdate = false;
mluis 0:cb80564f40e1 881 mibReq.Type = MIB_NETWORK_JOINED;
mluis 0:cb80564f40e1 882 LoRaMacMibGetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 883 SerialDisplayUpdateNetworkIsJoined( mibReq.Param.IsNetworkJoined );
mluis 0:cb80564f40e1 884 }
mluis 0:cb80564f40e1 885 if( Led1StateChanged == true )
mluis 0:cb80564f40e1 886 {
mluis 0:cb80564f40e1 887 Led1StateChanged = false;
mluis 0:cb80564f40e1 888 SerialDisplayUpdateLedState( 1, Led1State );
mluis 0:cb80564f40e1 889 }
mluis 0:cb80564f40e1 890 if( Led2StateChanged == true )
mluis 0:cb80564f40e1 891 {
mluis 0:cb80564f40e1 892 Led2StateChanged = false;
mluis 0:cb80564f40e1 893 SerialDisplayUpdateLedState( 2, Led2State );
mluis 0:cb80564f40e1 894 }
mluis 0:cb80564f40e1 895 if( Led3StateChanged == true )
mluis 0:cb80564f40e1 896 {
mluis 0:cb80564f40e1 897 Led3StateChanged = false;
mluis 0:cb80564f40e1 898 SerialDisplayUpdateLedState( 3, AppLedStateOn );
mluis 0:cb80564f40e1 899 }
mluis 0:cb80564f40e1 900 if( UplinkStatusUpdated == true )
mluis 0:cb80564f40e1 901 {
mluis 0:cb80564f40e1 902 UplinkStatusUpdated = false;
mluis 0:cb80564f40e1 903 SerialDisplayUpdateUplink( LoRaMacUplinkStatus.Acked, LoRaMacUplinkStatus.Datarate, LoRaMacUplinkStatus.UplinkCounter, LoRaMacUplinkStatus.Port, LoRaMacUplinkStatus.Buffer, LoRaMacUplinkStatus.BufferSize );
mluis 0:cb80564f40e1 904 }
mluis 0:cb80564f40e1 905 if( DownlinkStatusUpdated == true )
mluis 0:cb80564f40e1 906 {
mluis 0:cb80564f40e1 907 DownlinkStatusUpdated = false;
mluis 0:cb80564f40e1 908 SerialDisplayUpdateLedState( 2, Led2State );
mluis 0:cb80564f40e1 909 SerialDisplayUpdateDownlink( LoRaMacDownlinkStatus.RxData, LoRaMacDownlinkStatus.Rssi, LoRaMacDownlinkStatus.Snr, LoRaMacDownlinkStatus.DownlinkCounter, LoRaMacDownlinkStatus.Port, LoRaMacDownlinkStatus.Buffer, LoRaMacDownlinkStatus.BufferSize );
mluis 0:cb80564f40e1 910 }
mluis 0:cb80564f40e1 911
mluis 0:cb80564f40e1 912 switch( DeviceState )
mluis 0:cb80564f40e1 913 {
mluis 0:cb80564f40e1 914 case DEVICE_STATE_INIT:
mluis 0:cb80564f40e1 915 {
mluis 0:cb80564f40e1 916 LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
mluis 0:cb80564f40e1 917 LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
mluis 0:cb80564f40e1 918 LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
mluis 0:cb80564f40e1 919 LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
mluis 0:cb80564f40e1 920 LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks );
mluis 0:cb80564f40e1 921
mluis 0:cb80564f40e1 922 TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
mluis 0:cb80564f40e1 923
mluis 0:cb80564f40e1 924 TimerInit( &Led1Timer, OnLed1TimerEvent );
mluis 0:cb80564f40e1 925 TimerSetValue( &Led1Timer, 25000 );
mluis 0:cb80564f40e1 926
mluis 0:cb80564f40e1 927 TimerInit( &Led2Timer, OnLed2TimerEvent );
mluis 0:cb80564f40e1 928 TimerSetValue( &Led2Timer, 25000 );
mluis 0:cb80564f40e1 929
mluis 0:cb80564f40e1 930 mibReq.Type = MIB_ADR;
mluis 0:cb80564f40e1 931 mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
mluis 0:cb80564f40e1 932 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 933
mluis 0:cb80564f40e1 934 mibReq.Type = MIB_PUBLIC_NETWORK;
mluis 0:cb80564f40e1 935 mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
mluis 0:cb80564f40e1 936 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 937
spcores 1:c365eaf833bb 938 #if defined( USE_BAND_868 ) || defined( USE_BAND_865 )
mluis 0:cb80564f40e1 939 LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
mluis 0:cb80564f40e1 940 SerialDisplayUpdateDutyCycle( LORAWAN_DUTYCYCLE_ON );
mluis 0:cb80564f40e1 941 #endif
mluis 0:cb80564f40e1 942 SerialDisplayUpdateActivationMode( OVER_THE_AIR_ACTIVATION );
mluis 0:cb80564f40e1 943 SerialDisplayUpdateAdr( LORAWAN_ADR_ON );
mluis 0:cb80564f40e1 944 SerialDisplayUpdatePublicNetwork( LORAWAN_PUBLIC_NETWORK );
mluis 0:cb80564f40e1 945
mluis 0:cb80564f40e1 946 LoRaMacDownlinkStatus.DownlinkCounter = 0;
mluis 0:cb80564f40e1 947
mluis 0:cb80564f40e1 948 DeviceState = DEVICE_STATE_JOIN;
mluis 0:cb80564f40e1 949 break;
mluis 0:cb80564f40e1 950 }
mluis 0:cb80564f40e1 951 case DEVICE_STATE_JOIN:
mluis 0:cb80564f40e1 952 {
mluis 0:cb80564f40e1 953 #if( OVER_THE_AIR_ACTIVATION != 0 )
mluis 0:cb80564f40e1 954 MlmeReq_t mlmeReq;
mluis 0:cb80564f40e1 955
mluis 0:cb80564f40e1 956 mlmeReq.Type = MLME_JOIN;
mluis 0:cb80564f40e1 957
mluis 0:cb80564f40e1 958 mlmeReq.Req.Join.DevEui = DevEui;
mluis 0:cb80564f40e1 959 mlmeReq.Req.Join.AppEui = AppEui;
mluis 0:cb80564f40e1 960 mlmeReq.Req.Join.AppKey = AppKey;
mluis 0:cb80564f40e1 961
mluis 0:cb80564f40e1 962 if( NextTx == true )
mluis 0:cb80564f40e1 963 {
mluis 0:cb80564f40e1 964 LoRaMacMlmeRequest( &mlmeReq );
mluis 0:cb80564f40e1 965 }
mluis 0:cb80564f40e1 966
mluis 0:cb80564f40e1 967 SerialDisplayUpdateEui( 5, DevEui );
mluis 0:cb80564f40e1 968 SerialDisplayUpdateEui( 6, AppEui );
mluis 0:cb80564f40e1 969 SerialDisplayUpdateKey( 7, AppKey );
mluis 0:cb80564f40e1 970
mluis 0:cb80564f40e1 971 // Schedule next packet transmission
mluis 0:cb80564f40e1 972 TxDutyCycleTime = OVER_THE_AIR_ACTIVATION_DUTYCYCLE;
mluis 0:cb80564f40e1 973 DeviceState = DEVICE_STATE_CYCLE;
mluis 0:cb80564f40e1 974
mluis 0:cb80564f40e1 975 #else
mluis 0:cb80564f40e1 976 mibReq.Type = MIB_NET_ID;
mluis 0:cb80564f40e1 977 mibReq.Param.NetID = LORAWAN_NETWORK_ID;
mluis 0:cb80564f40e1 978 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 979
mluis 0:cb80564f40e1 980 mibReq.Type = MIB_DEV_ADDR;
mluis 0:cb80564f40e1 981 mibReq.Param.DevAddr = DevAddr;
mluis 0:cb80564f40e1 982 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 983
mluis 0:cb80564f40e1 984 mibReq.Type = MIB_NWK_SKEY;
mluis 0:cb80564f40e1 985 mibReq.Param.NwkSKey = NwkSKey;
mluis 0:cb80564f40e1 986 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 987
mluis 0:cb80564f40e1 988 mibReq.Type = MIB_APP_SKEY;
mluis 0:cb80564f40e1 989 mibReq.Param.AppSKey = AppSKey;
mluis 0:cb80564f40e1 990 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 991
mluis 0:cb80564f40e1 992 mibReq.Type = MIB_NETWORK_JOINED;
mluis 0:cb80564f40e1 993 mibReq.Param.IsNetworkJoined = true;
mluis 0:cb80564f40e1 994 LoRaMacMibSetRequestConfirm( &mibReq );
mluis 0:cb80564f40e1 995
mluis 0:cb80564f40e1 996 SerialDisplayUpdateNwkId( LORAWAN_NETWORK_ID );
mluis 0:cb80564f40e1 997 SerialDisplayUpdateDevAddr( DevAddr );
mluis 0:cb80564f40e1 998 SerialDisplayUpdateKey( 12, NwkSKey );
mluis 0:cb80564f40e1 999 SerialDisplayUpdateKey( 13, AppSKey );
mluis 0:cb80564f40e1 1000
mluis 0:cb80564f40e1 1001 DeviceState = DEVICE_STATE_SEND;
mluis 0:cb80564f40e1 1002 #endif
mluis 0:cb80564f40e1 1003 IsNetworkJoinedStatusUpdate = true;
mluis 0:cb80564f40e1 1004 break;
mluis 0:cb80564f40e1 1005 }
mluis 0:cb80564f40e1 1006 case DEVICE_STATE_SEND:
mluis 0:cb80564f40e1 1007 {
mluis 0:cb80564f40e1 1008 if( NextTx == true )
mluis 0:cb80564f40e1 1009 {
mluis 0:cb80564f40e1 1010 SerialDisplayUpdateUplinkAcked( false );
mluis 0:cb80564f40e1 1011 SerialDisplayUpdateDonwlinkRxData( false );
mluis 0:cb80564f40e1 1012 PrepareTxFrame( AppPort );
mluis 0:cb80564f40e1 1013
mluis 0:cb80564f40e1 1014 NextTx = SendFrame( );
mluis 0:cb80564f40e1 1015
mluis 0:cb80564f40e1 1016 // Switch LED 1 ON
mluis 0:cb80564f40e1 1017 Led1State = true;
mluis 0:cb80564f40e1 1018 Led1StateChanged = true;
mluis 0:cb80564f40e1 1019 TimerStart( &Led1Timer );
mluis 0:cb80564f40e1 1020 }
mluis 0:cb80564f40e1 1021 if( ComplianceTest.Running == true )
mluis 0:cb80564f40e1 1022 {
mluis 0:cb80564f40e1 1023 // Schedule next packet transmission as soon as possible
mluis 0:cb80564f40e1 1024 TxDutyCycleTime = 1000; // 1 ms
mluis 0:cb80564f40e1 1025 }
mluis 0:cb80564f40e1 1026 else
mluis 0:cb80564f40e1 1027 {
mluis 0:cb80564f40e1 1028 // Schedule next packet transmission
mluis 0:cb80564f40e1 1029 TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
mluis 0:cb80564f40e1 1030 }
mluis 0:cb80564f40e1 1031 DeviceState = DEVICE_STATE_CYCLE;
mluis 0:cb80564f40e1 1032 break;
mluis 0:cb80564f40e1 1033 }
mluis 0:cb80564f40e1 1034 case DEVICE_STATE_CYCLE:
mluis 0:cb80564f40e1 1035 {
mluis 0:cb80564f40e1 1036 // Schedule next packet transmission
mluis 0:cb80564f40e1 1037 TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
mluis 0:cb80564f40e1 1038 TimerStart( &TxNextPacketTimer );
mluis 0:cb80564f40e1 1039
mluis 0:cb80564f40e1 1040 DeviceState = DEVICE_STATE_SLEEP;
mluis 0:cb80564f40e1 1041 break;
mluis 0:cb80564f40e1 1042 }
mluis 0:cb80564f40e1 1043 case DEVICE_STATE_SLEEP:
mluis 0:cb80564f40e1 1044 {
mluis 0:cb80564f40e1 1045 // Wake up through events
mluis 0:cb80564f40e1 1046 break;
mluis 0:cb80564f40e1 1047 }
mluis 0:cb80564f40e1 1048 default:
mluis 0:cb80564f40e1 1049 {
mluis 0:cb80564f40e1 1050 DeviceState = DEVICE_STATE_INIT;
mluis 0:cb80564f40e1 1051 break;
mluis 0:cb80564f40e1 1052 }
mluis 0:cb80564f40e1 1053
mluis 0:cb80564f40e1 1054 }
mluis 0:cb80564f40e1 1055 }
mluis 0:cb80564f40e1 1056 }