PIR + LoRa
Dependencies: BLE_API LMiC SX1276Lib mbed nRF51822 nrf51_rtc
Fork of BLE_PhysicalWeb by
main.cpp
- Committer:
- janjongboom
- Date:
- 2015-09-24
- Revision:
- 12:940eb88a2104
- Parent:
- 11:bbe4157401e2
File content as of revision 12:940eb88a2104:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed.h" #include "BLEDevice.h" #include "URIBeaconConfigService.h" #include "DFUService.h" #include "DeviceInformationService.h" #include "nrf51_rtc/nrf51_rtc.h" #include "lmic.h" #include "oslmic.h" #include "debug.h" /*! * When set to 1 the application uses the Over-the-Air activation procedure * When set to 0 the application uses the Personalization activation procedure */ #define OVER_THE_AIR_ACTIVATION 1 #if( OVER_THE_AIR_ACTIVATION == 0 ) /*! * Defines the network ID when using personalization activation procedure */ #define LORAWAN_NET_ID ( uint32_t )0x00000000 /*! * Defines the device address when using personalization activation procedure */ #define LORAWAN_DEV_ADDR ( uint32_t )0x73318891 #endif /*! * Defines the application data transmission duty cycle */ #define APP_TX_DUTYCYCLE 5000 // 5 [s] value in ms #define APP_TX_DUTYCYCLE_RND 1000 // 1 [s] value in ms /*! * LoRaWAN Adaptative Data Rate */ #define LORAWAN_ADR_ON 1 /*! * LoRaWAN confirmed messages */ #define LORAWAN_CONFIRMED_MSG_ON 0 /*! * LoRaWAN application port */ #define LORAWAN_APP_PORT 2 /*! * User application data buffer size */ #if ( LORAWAN_CONFIRMED_MSG_ON == 1 ) #define LORAWAN_APP_DATA_SIZE 9 #else #define LORAWAN_APP_DATA_SIZE 4 #endif ////////////////////////////////////////////////// // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW) ////////////////////////////////////////////////// // application router ID (LSBF) static const uint8_t AppEui[8] = { // 13-37-aa-bb-cc-dd-ee-ff 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x37, 0x13 // so its read rtl in the NS so when creating need to flip it in server // compared to here. Really weird. }; // unique device ID (LSBF) static const u1_t DevEui[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; // device-specific AES key (derived from device EUI) static const uint8_t DevKey[16] = { 0xC1, 0x20, 0x2B, 0xB0, 0xAE, 0x97, 0x20, 0xC8, 0x18, 0xA3, 0x0F, 0xFA, 0x05, 0x14, 0xC5, 0x4F }; #if( OVER_THE_AIR_ACTIVATION == 0 ) // network session key static uint8_t NwkSKey[] = { 0x50, 0x12, 0x78, 0x26, 0x23, 0x9A, 0x5E, 0x39, 0x86, 0x8A, 0xCA, 0x7B, 0xDE, 0x16, 0xE1, 0x32 }; static uint8_t ArtSKey[] = { 0x54, 0xEB, 0x54, 0x4B, 0x07, 0x0C, 0x10, 0x69, 0xB1, 0x44, 0x94, 0x44, 0xF1, 0xCC, 0x13, 0xDA }; #endif Serial pc(USBTX, USBRX); // tx, rx // LEDs and Frame jobs osjob_t rxLedJob; osjob_t txLedJob; osjob_t sendFrameJob; // LED state static bool AppLedStateOn = false; ////////////////////////////////////////////////// // Utility functions ////////////////////////////////////////////////// /*! * \brief Computes a random number between min and max * * \param [IN] min range minimum value * \param [IN] max range maximum value * \retval random random value in range min..max */ int32_t randr( int32_t min, int32_t max ) { return ( int32_t )rand( ) % ( max - min + 1 ) + min; } ////////////////////////////////////////////////// // APPLICATION CALLBACKS ////////////////////////////////////////////////// // provide application router ID (8 bytes, LSBF) void os_getArtEui( uint8_t *buf ) { memcpy( buf, AppEui, 8 ); } // provide device ID (8 bytes, LSBF) void os_getDevEui( uint8_t *buf ) { memcpy( buf, DevEui, 8 ); } // provide device key (16 bytes) void os_getDevKey( uint8_t *buf ) { memcpy( buf, DevKey, 16 ); } ////////////////////////////////////////////////// // MAIN - INITIALIZATION AND STARTUP ////////////////////////////////////////////////// static void onRxLed( osjob_t* j ) { debug_val("LED2 = ", 0 ); } static void onTxLed( osjob_t* j ) { debug_val("LED1 = ", 0 ); } bool rise_state = false; uint16_t last_rise = 0; static void prepareTxFrame( void ) { uint16_t seconds_ago = rtc.time() - last_rise; LMIC.frame[0] = 0x02; // PIR sensor LMIC.frame[1] = rise_state ? 1 : 0; LMIC.frame[2] = ( seconds_ago >> 8 ) & 0xFF; LMIC.frame[3] = seconds_ago & 0xFF; printf("prepareTxFrame %02x %02x %02x %02x\r\n", LMIC.frame[0], LMIC.frame[1], LMIC.frame[2], LMIC.frame[3]); #if ( LORAWAN_CONFIRMED_MSG_ON == 1 ) LMIC.frame[4] = LMIC.seqnoDn >> 8; LMIC.frame[5] = LMIC.seqnoDn; LMIC.frame[6] = LMIC.rssi >> 8; LMIC.frame[7] = LMIC.rssi; LMIC.frame[8] = LMIC.snr; #endif } static void prepareTxFrameLoRaMote( void ) { pc.printf("prepareTxFrameLoRaMote\r\n"); uint16_t pressure = 0; int16_t altitudeBar = 0; int16_t temperature = 0; int32_t latitude, longitude = 0; uint16_t altitudeGps = 0xFFFF; uint8_t batteryLevel = 0; pressure = 10132; // in hPa / 10 temperature = 2300; // in °C * 100 altitudeBar = 70; // in m * 10 batteryLevel = 160; // 1 (very low) to 254 (fully charged) altitudeGps = 73; // in m LMIC.frame[0] = AppLedStateOn; LMIC.frame[1] = ( pressure >> 8 ) & 0xFF; LMIC.frame[2] = pressure & 0xFF; LMIC.frame[3] = ( temperature >> 8 ) & 0xFF; LMIC.frame[4] = temperature & 0xFF; LMIC.frame[5] = ( altitudeBar >> 8 ) & 0xFF; LMIC.frame[6] = altitudeBar & 0xFF; LMIC.frame[7] = batteryLevel; LMIC.frame[8] = ( latitude >> 16 ) & 0xFF; LMIC.frame[9] = ( latitude >> 8 ) & 0xFF; LMIC.frame[10] = latitude & 0xFF; LMIC.frame[11] = ( longitude >> 16 ) & 0xFF; LMIC.frame[12] = ( longitude >> 8 ) & 0xFF; LMIC.frame[13] = longitude & 0xFF; LMIC.frame[14] = ( altitudeGps >> 8 ) & 0xFF; LMIC.frame[15] = altitudeGps & 0xFF; #if ( LORAWAN_CONFIRMED_MSG_ON == 1 ) LMIC.frame[16] = LMIC.seqnoDn >> 8; LMIC.frame[17] = LMIC.seqnoDn; LMIC.frame[18] = LMIC.rssi >> 8; LMIC.frame[19] = LMIC.rssi; LMIC.frame[20] = LMIC.snr; #endif } DigitalOut led2(LED2); void processRxFrame( void ) { switch( LMIC.frame[LMIC.dataBeg - 1] ) // Check Rx port number { case 1: // The application LED can be controlled on port 1 or 2 case 2: if( LMIC.dataLen == 1 ) { AppLedStateOn = LMIC.frame[LMIC.dataBeg] & 0x01; led2 = AppLedStateOn; debug_val( "LED3 = ", AppLedStateOn ); } break; default: break; } } static void onSendFrame( osjob_t* j ) { prepareTxFrame( ); LMIC_setTxData2( LORAWAN_APP_PORT, LMIC.frame, LORAWAN_APP_DATA_SIZE, LORAWAN_CONFIRMED_MSG_ON ); // Blink Tx LED debug_val( "LED1 = ", 1 ); os_setTimedCallback( &txLedJob, os_getTime( ) + ms2osticks( 25 ), onTxLed ); } // Initialization job static void onInit( osjob_t* j ) { // reset MAC state LMIC_reset( ); LMIC_setAdrMode( LORAWAN_ADR_ON ); LMIC_setDrTxpow( DR_SF12, 14 ); // start joining #if( OVER_THE_AIR_ACTIVATION != 0 ) pc.printf("startJoining\n"); LMIC_startJoining( ); #else pc.printf("gonne send a frame yo\n"); LMIC_setSession( LORAWAN_NET_ID, LORAWAN_DEV_ADDR, NwkSKey, ArtSKey ); onSendFrame( NULL ); #endif // init done - onEvent( ) callback will be invoked... } //int main( void ) //{ // osjob_t initjob; // // // initialize runtime env // os_init( ); // // setup initial job // os_setCallback( &initjob, onInit ); // // execute scheduled jobs and events // os_runloop( ); // // (not reached) //} ////////////////////////////////////////////////// // LMIC EVENT CALLBACK ////////////////////////////////////////////////// void onEvent( ev_t ev ) { pc.printf("onEvent\r\n"); bool txOn = false; debug_event( ev ); switch( ev ) { // network joined, session established case EV_JOINED: pc.printf("Joined, ID=%d\n", LMIC.netid); debug_val( "Net ID = ", LMIC.netid ); txOn = true; break; // scheduled data sent (optionally data received) case EV_TXCOMPLETE: pc.printf("TXComplete, datarate=%d\n", LMIC.datarate); debug_val( "Datarate = ", LMIC.datarate ); // Check if we have a downlink on either Rx1 or Rx2 windows if( ( LMIC.txrxFlags & ( TXRX_DNW1 | TXRX_DNW2 ) ) != 0 ) { debug_val( "LED2 = ", 1 ); os_setTimedCallback( &rxLedJob, os_getTime( ) + ms2osticks( 25 ), onRxLed ); if( LMIC.dataLen != 0 ) { // data received in rx slot after tx debug_buf( LMIC.frame + LMIC.dataBeg, LMIC.dataLen ); processRxFrame( ); } } txOn = true; break; default: break; } if( txOn == true ) { //Sends frame every APP_TX_DUTYCYCLE +/- APP_TX_DUTYCYCLE_RND random time (if not duty cycle limited) os_setTimedCallback( &sendFrameJob, os_getTime( ) + ms2osticks( APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ) ), onSendFrame ); ////Sends frame as soon as possible (duty cylce limitations) //onSendFrame( NULL ); } } InterruptIn motion(p7); DigitalOut led(LED4); BLEDevice ble; URIBeaconConfigService *uriBeaconConfig; void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) { ble.startAdvertising(); } void riseHandler(void) { led = 0; pc.printf("rise\r\n"); last_rise = rtc.time(); rise_state = true; } void fallHandler(void) { led = 1; pc.printf("fall\r\n"); last_rise = rtc.time(); rise_state = false; } void lastRiseCallback(void) { pc.printf("Current state %d, last_rise %d\r\n", rise_state, rtc.time() - last_rise); } void run_ble() { ble.init(); ble.onDisconnection(disconnectionCallback); uriBeaconConfig = new URIBeaconConfigService(ble, "http://goo.gl/H9YK6O"); if (!uriBeaconConfig->configuredSuccessfully()) { error("failed to accommodate URI"); } /* optional use of the API offered by URIBeaconConfigService */ const int8_t powerLevels[] = {-20, -4, 0, 10}; uriBeaconConfig->setTxPowerLevels(powerLevels); uriBeaconConfig->setTxPowerMode(URIBeaconConfigService::TX_POWER_MODE_HIGH); static const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; static const uint8_t urldata[] = { BEACON_UUID[0], BEACON_UUID[1], 0x00, // flags 0x20, // power 0x00, // http://www. 'g', 'o', 'o', '.', 'g', 'l', '/', 'H', '9', 'Y', 'K', '6', 'O', }; ble.clearAdvertisingPayload(); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, urldata, sizeof(urldata)); ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); ble.setAdvertisingInterval(800); /* .5s; in multiples of 0.625ms. */ ble.startAdvertising(); } int main(void) { Ticker ticker; ticker.attach(&lastRiseCallback, 10); motion.rise(&riseHandler); motion.fall(&fallHandler); run_ble(); // run_ble(); // osjob_t initjob; //// // // initialize runtime env // os_init( ); // // setup initial job // os_setCallback( &initjob, onInit ); // // os_runloop(); while (true) { // execute scheduled jobs and events // os_inner_loop(); ble.waitForEvent(); } // os_runloop( ); // (not reached) }