PIR + LoRa

Dependencies:   BLE_API LMiC SX1276Lib mbed nRF51822 nrf51_rtc

Fork of BLE_PhysicalWeb by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "BLEDevice.h"
00019 #include "URIBeaconConfigService.h"
00020 #include "DFUService.h"
00021 #include "DeviceInformationService.h"
00022 #include "nrf51_rtc/nrf51_rtc.h"
00023 
00024 #include "lmic.h"
00025 #include "oslmic.h"
00026 #include "debug.h"
00027 
00028 /*!
00029  * When set to 1 the application uses the Over-the-Air activation procedure
00030  * When set to 0 the application uses the Personalization activation procedure
00031  */
00032 #define OVER_THE_AIR_ACTIVATION                     1
00033 
00034 #if( OVER_THE_AIR_ACTIVATION == 0 )
00035 
00036 /*!
00037  * Defines the network ID when using personalization activation procedure
00038  */
00039 #define LORAWAN_NET_ID                              ( uint32_t )0x00000000
00040 
00041 /*!
00042  * Defines the device address when using personalization activation procedure
00043  */
00044 #define LORAWAN_DEV_ADDR                            ( uint32_t )0x73318891
00045 
00046 #endif
00047 
00048 /*!
00049  * Defines the application data transmission duty cycle
00050  */
00051 #define APP_TX_DUTYCYCLE                            5000 // 5 [s] value in ms
00052 #define APP_TX_DUTYCYCLE_RND                        1000 // 1 [s] value in ms
00053 
00054 /*!
00055  * LoRaWAN Adaptative Data Rate
00056  */
00057 #define LORAWAN_ADR_ON                              1
00058 
00059 /*!
00060  * LoRaWAN confirmed messages
00061  */
00062 #define LORAWAN_CONFIRMED_MSG_ON                    0
00063 
00064 /*!
00065  * LoRaWAN application port
00066  */
00067 #define LORAWAN_APP_PORT                            2
00068 
00069 /*!
00070  * User application data buffer size
00071  */
00072 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
00073 #define LORAWAN_APP_DATA_SIZE                       9
00074 
00075 #else
00076 #define LORAWAN_APP_DATA_SIZE                       4
00077 
00078 #endif
00079 
00080 //////////////////////////////////////////////////
00081 // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW)
00082 //////////////////////////////////////////////////
00083 
00084 // application router ID (LSBF)
00085 static const uint8_t AppEui[8] =
00086 { // 13-37-aa-bb-cc-dd-ee-ff
00087     0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x37, 0x13
00088     // so its read rtl in the NS so when creating need to flip it in server
00089     // compared to here. Really weird.
00090 };
00091 
00092 // unique device ID (LSBF)
00093 static const u1_t DevEui[8] =
00094 {
00095     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
00096 };
00097 
00098 // device-specific AES key (derived from device EUI)
00099 static const uint8_t DevKey[16] =
00100 {
00101     0xC1, 0x20, 0x2B, 0xB0, 0xAE, 0x97, 0x20, 0xC8,
00102     0x18, 0xA3, 0x0F, 0xFA, 0x05, 0x14, 0xC5, 0x4F
00103 };
00104 
00105 #if( OVER_THE_AIR_ACTIVATION == 0 )
00106 // network session key
00107 static uint8_t NwkSKey[] =
00108 {
00109     0x50, 0x12, 0x78, 0x26, 0x23, 0x9A, 0x5E, 0x39,
00110     0x86, 0x8A, 0xCA, 0x7B, 0xDE, 0x16, 0xE1, 0x32
00111 };
00112 static uint8_t ArtSKey[] =
00113 {
00114     0x54, 0xEB, 0x54, 0x4B, 0x07, 0x0C, 0x10, 0x69,
00115     0xB1, 0x44, 0x94, 0x44, 0xF1, 0xCC, 0x13, 0xDA
00116 };
00117 
00118 #endif
00119 
00120 Serial pc(USBTX, USBRX); // tx, rx
00121 
00122 // LEDs and Frame jobs
00123 osjob_t rxLedJob;
00124 osjob_t txLedJob;
00125 osjob_t sendFrameJob;
00126 
00127 // LED state
00128 static bool AppLedStateOn = false;
00129 
00130 //////////////////////////////////////////////////
00131 // Utility functions
00132 //////////////////////////////////////////////////
00133 /*!
00134  * \brief Computes a random number between min and max
00135  *
00136  * \param [IN] min range minimum value
00137  * \param [IN] max range maximum value
00138  * \retval random random value in range min..max
00139  */
00140 int32_t randr( int32_t min, int32_t max )
00141 {
00142     return ( int32_t )rand( ) % ( max - min + 1 ) + min;
00143 }
00144 
00145 //////////////////////////////////////////////////
00146 // APPLICATION CALLBACKS
00147 //////////////////////////////////////////////////
00148 
00149 // provide application router ID (8 bytes, LSBF)
00150 void os_getArtEui( uint8_t *buf )
00151 {
00152     memcpy( buf, AppEui, 8 );
00153 }
00154 
00155 // provide device ID (8 bytes, LSBF)
00156 void os_getDevEui( uint8_t *buf )
00157 {
00158     memcpy( buf, DevEui, 8 );
00159 }
00160 
00161 // provide device key (16 bytes)
00162 void os_getDevKey( uint8_t *buf )
00163 {
00164     memcpy( buf, DevKey, 16 );
00165 }
00166 
00167 //////////////////////////////////////////////////
00168 // MAIN - INITIALIZATION AND STARTUP
00169 //////////////////////////////////////////////////
00170 
00171 static void onRxLed( osjob_t* j )
00172 {
00173     debug_val("LED2 = ", 0 );
00174 }
00175 
00176 static void onTxLed( osjob_t* j )
00177 {
00178     debug_val("LED1 = ", 0 );
00179 }
00180 
00181 bool rise_state = false;
00182 uint16_t last_rise = 0;
00183 
00184 static void prepareTxFrame( void )
00185 {
00186     uint16_t seconds_ago = rtc.time() - last_rise;
00187     
00188     LMIC.frame[0] = 0x02; // PIR sensor
00189     LMIC.frame[1] = rise_state ? 1 : 0;
00190     LMIC.frame[2] = ( seconds_ago >> 8 ) & 0xFF;
00191     LMIC.frame[3] = seconds_ago & 0xFF;
00192     
00193     printf("prepareTxFrame %02x %02x %02x %02x\r\n", 
00194         LMIC.frame[0], LMIC.frame[1], LMIC.frame[2], LMIC.frame[3]);
00195     
00196 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
00197     LMIC.frame[4] = LMIC.seqnoDn >> 8;
00198     LMIC.frame[5] = LMIC.seqnoDn;
00199     LMIC.frame[6] = LMIC.rssi >> 8;
00200     LMIC.frame[7] = LMIC.rssi;
00201     LMIC.frame[8] = LMIC.snr;
00202 #endif
00203 }
00204 
00205 static void prepareTxFrameLoRaMote( void )
00206 {
00207     pc.printf("prepareTxFrameLoRaMote\r\n");
00208     
00209     uint16_t pressure = 0;
00210     int16_t altitudeBar = 0;
00211     int16_t temperature = 0;
00212     int32_t latitude, longitude = 0;
00213     uint16_t altitudeGps = 0xFFFF;
00214     uint8_t batteryLevel = 0;
00215     
00216     pressure = 10132;             // in hPa / 10
00217     temperature = 2300;       // in °C * 100
00218     altitudeBar = 70;           // in m * 10
00219     batteryLevel = 160;                        // 1 (very low) to 254 (fully charged)
00220     altitudeGps = 73;                           // in m
00221     
00222     LMIC.frame[0] = AppLedStateOn;
00223     LMIC.frame[1] = ( pressure >> 8 ) & 0xFF;
00224     LMIC.frame[2] = pressure & 0xFF;
00225     LMIC.frame[3] = ( temperature >> 8 ) & 0xFF;
00226     LMIC.frame[4] = temperature & 0xFF;
00227     LMIC.frame[5] = ( altitudeBar >> 8 ) & 0xFF;
00228     LMIC.frame[6] = altitudeBar & 0xFF;
00229     LMIC.frame[7] = batteryLevel;
00230     LMIC.frame[8] = ( latitude >> 16 ) & 0xFF;
00231     LMIC.frame[9] = ( latitude >> 8 ) & 0xFF;
00232     LMIC.frame[10] = latitude & 0xFF;
00233     LMIC.frame[11] = ( longitude >> 16 ) & 0xFF;
00234     LMIC.frame[12] = ( longitude >> 8 ) & 0xFF;
00235     LMIC.frame[13] = longitude & 0xFF;
00236     LMIC.frame[14] = ( altitudeGps >> 8 ) & 0xFF;
00237     LMIC.frame[15] = altitudeGps & 0xFF;
00238 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
00239     LMIC.frame[16] = LMIC.seqnoDn >> 8;
00240     LMIC.frame[17] = LMIC.seqnoDn;
00241     LMIC.frame[18] = LMIC.rssi >> 8;
00242     LMIC.frame[19] = LMIC.rssi;
00243     LMIC.frame[20] = LMIC.snr;
00244 #endif    
00245 }
00246 
00247 DigitalOut led2(LED2);
00248 
00249 void processRxFrame( void )
00250 {
00251     switch( LMIC.frame[LMIC.dataBeg - 1] ) // Check Rx port number
00252     {
00253         case 1: // The application LED can be controlled on port 1 or 2
00254         case 2:
00255             if( LMIC.dataLen == 1 )
00256             {
00257                 AppLedStateOn = LMIC.frame[LMIC.dataBeg] & 0x01;
00258                 led2 = AppLedStateOn;
00259                 debug_val( "LED3 = ", AppLedStateOn );
00260             }
00261             break;
00262         default:
00263             break;
00264     }
00265 }
00266 
00267 static void onSendFrame( osjob_t* j )
00268 {
00269     prepareTxFrame( );
00270     LMIC_setTxData2( LORAWAN_APP_PORT, LMIC.frame, LORAWAN_APP_DATA_SIZE, LORAWAN_CONFIRMED_MSG_ON );
00271 
00272     // Blink Tx LED
00273     debug_val( "LED1 = ", 1 );
00274     os_setTimedCallback( &txLedJob, os_getTime( ) + ms2osticks( 25 ), onTxLed );
00275 }
00276 
00277 // Initialization job
00278 static void onInit( osjob_t* j )
00279 {
00280     // reset MAC state
00281     LMIC_reset( );
00282     LMIC_setAdrMode( LORAWAN_ADR_ON );
00283     LMIC_setDrTxpow( DR_SF12, 14 );
00284 
00285     // start joining
00286 #if( OVER_THE_AIR_ACTIVATION != 0 )
00287     pc.printf("startJoining\n");
00288     LMIC_startJoining( );
00289 #else
00290     pc.printf("gonne send a frame yo\n");
00291     LMIC_setSession( LORAWAN_NET_ID, LORAWAN_DEV_ADDR, NwkSKey, ArtSKey );
00292     onSendFrame( NULL );
00293 #endif
00294     // init done - onEvent( ) callback will be invoked...
00295 }
00296 
00297 //int main( void )
00298 //{
00299 //    osjob_t initjob;
00300 //
00301 //    // initialize runtime env
00302 //    os_init( );
00303 //    // setup initial job
00304 //    os_setCallback( &initjob, onInit );
00305 //    // execute scheduled jobs and events
00306 //    os_runloop( );
00307 //    // (not reached)
00308 //}
00309 
00310 //////////////////////////////////////////////////
00311 // LMIC EVENT CALLBACK
00312 //////////////////////////////////////////////////
00313 void onEvent( ev_t ev )
00314 {
00315     pc.printf("onEvent\r\n");
00316     bool txOn = false;
00317     debug_event( ev );
00318 
00319     switch( ev ) 
00320     {
00321     // network joined, session established
00322     case EV_JOINED:
00323         pc.printf("Joined, ID=%d\n", LMIC.netid);
00324         debug_val( "Net ID = ", LMIC.netid );
00325         txOn = true;
00326         break;
00327     // scheduled data sent (optionally data received)
00328     case EV_TXCOMPLETE:
00329         pc.printf("TXComplete, datarate=%d\n", LMIC.datarate);
00330         debug_val( "Datarate = ", LMIC.datarate );
00331         // Check if we have a downlink on either Rx1 or Rx2 windows
00332         if( ( LMIC.txrxFlags & ( TXRX_DNW1 | TXRX_DNW2 ) ) != 0 )
00333         {
00334             debug_val( "LED2 = ", 1 );
00335             os_setTimedCallback( &rxLedJob, os_getTime( ) + ms2osticks( 25 ), onRxLed );
00336 
00337             if( LMIC.dataLen != 0 )
00338             { // data received in rx slot after tx
00339                 debug_buf( LMIC.frame + LMIC.dataBeg, LMIC.dataLen );
00340                 processRxFrame( );
00341             }
00342         }
00343         txOn = true;
00344         break;
00345     default:
00346         break;
00347     }
00348     if( txOn == true )
00349     {
00350         //Sends frame every APP_TX_DUTYCYCLE +/- APP_TX_DUTYCYCLE_RND random time (if not duty cycle limited)
00351         os_setTimedCallback( &sendFrameJob,
00352                              os_getTime( ) + ms2osticks( APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ) ),
00353                              onSendFrame );
00354         
00355         ////Sends frame as soon as possible (duty cylce limitations)
00356         //onSendFrame( NULL );
00357     }
00358 }
00359 
00360 
00361 InterruptIn motion(p7);
00362 DigitalOut led(LED4); 
00363 
00364 BLEDevice ble;
00365 URIBeaconConfigService *uriBeaconConfig;
00366 
00367 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
00368 {
00369     ble.startAdvertising();
00370 }
00371 
00372 void riseHandler(void)
00373 {
00374     led = 0;
00375     pc.printf("rise\r\n");
00376     last_rise = rtc.time();
00377     rise_state = true;
00378 }
00379 
00380 void fallHandler(void)
00381 {
00382     led = 1;
00383     pc.printf("fall\r\n");
00384     last_rise = rtc.time();
00385     rise_state = false;
00386 }
00387 
00388 void lastRiseCallback(void)
00389 {
00390     pc.printf("Current state %d, last_rise %d\r\n", rise_state, rtc.time() - last_rise);
00391 }
00392 
00393 void run_ble() {
00394     ble.init();
00395     ble.onDisconnection(disconnectionCallback);
00396 
00397     uriBeaconConfig = new URIBeaconConfigService(ble, "http://goo.gl/H9YK6O");
00398     if (!uriBeaconConfig->configuredSuccessfully()) {
00399         error("failed to accommodate URI");
00400     }
00401     /* optional use of the API offered by URIBeaconConfigService */
00402     const int8_t powerLevels[] = {-20, -4, 0, 10};
00403     uriBeaconConfig->setTxPowerLevels(powerLevels);
00404     uriBeaconConfig->setTxPowerMode(URIBeaconConfigService::TX_POWER_MODE_HIGH);
00405 
00406     static const uint8_t BEACON_UUID[] = {0xD8, 0xFE};
00407     static const uint8_t urldata[] = {
00408         BEACON_UUID[0],
00409         BEACON_UUID[1],
00410         0x00, // flags
00411         0x20, // power
00412         0x00, // http://www.
00413         'g',
00414         'o',
00415         'o',
00416         '.',
00417         'g',
00418         'l',
00419         '/',
00420         'H',
00421         '9',
00422         'Y',
00423         'K',
00424         '6',
00425         'O',
00426     };
00427 
00428     ble.clearAdvertisingPayload();
00429     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID));
00430     ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, urldata, sizeof(urldata));
00431 
00432     ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
00433     ble.setAdvertisingInterval(800); /* .5s; in multiples of 0.625ms. */
00434     ble.startAdvertising();
00435 }
00436 
00437 int main(void)
00438 {    
00439     Ticker ticker;
00440     ticker.attach(&lastRiseCallback, 10);
00441 
00442     motion.rise(&riseHandler);
00443     motion.fall(&fallHandler);
00444     
00445     run_ble();
00446     
00447 //    run_ble();
00448     
00449 //    osjob_t initjob;
00450 ////
00451 //    // initialize runtime env
00452 //    os_init( );
00453 //    // setup initial job
00454 //    os_setCallback( &initjob, onInit );
00455 //    
00456 //    os_runloop();
00457 
00458     while (true) {
00459         // execute scheduled jobs and events
00460 //        os_inner_loop();
00461         ble.waitForEvent();
00462     }
00463 
00464 
00465     
00466 //    os_runloop( );
00467     // (not reached)
00468 }