PIR + LoRa
Dependencies: BLE_API LMiC SX1276Lib mbed nRF51822 nrf51_rtc
Fork of BLE_PhysicalWeb by
Diff: main.cpp
- Revision:
- 11:bbe4157401e2
- Parent:
- 10:e7ab33223964
- Child:
- 12:940eb88a2104
--- a/main.cpp Fri Jul 31 14:29:36 2015 +0000 +++ b/main.cpp Mon Aug 03 13:18:24 2015 +0000 @@ -21,10 +21,344 @@ #include "DeviceInformationService.h" #include "nrf51_rtc/nrf51_rtc.h" -InterruptIn motion(p21); -DigitalOut led(LED1); +#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 0 + +#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 )0x73318881 + +#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] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// 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] = +{ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C +}; + +#if( OVER_THE_AIR_ACTIVATION == 0 ) +// network session key +static uint8_t NwkSKey[] = +{ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C +}; + +// application session key +static uint8_t ArtSKey[] = +{ + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C +}; + +#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: + debug_val( "Net ID = ", LMIC.netid ); + txOn = true; + break; + // scheduled data sent (optionally data received) + case EV_TXCOMPLETE: + 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; @@ -33,9 +367,6 @@ ble.startAdvertising(); } -bool rise_state = false; -time_t last_rise = 0; - void riseHandler(void) { led = 0; @@ -64,11 +395,11 @@ motion.rise(&riseHandler); motion.fall(&fallHandler); - +// ble.init(); ble.onDisconnection(disconnectionCallback); - uriBeaconConfig = new URIBeaconConfigService(ble, "http://goo.gl/K1PDnX"); + uriBeaconConfig = new URIBeaconConfigService(ble, "http://goo.gl/kFE6eY"); if (!uriBeaconConfig->configuredSuccessfully()) { error("failed to accommodate URI"); } @@ -83,7 +414,7 @@ BEACON_UUID[1], 0x00, // flags 0x20, // power - 0x00, // http://www. // https://goo.gl/K1PDnX + 0x00, // http://www. 'g', 'o', 'o', @@ -91,12 +422,12 @@ 'g', 'l', '/', - 'K', - '1', - 'P', - 'D', - 'n', - 'X', + 'k', + 'F', + 'E', + '6', + 'e', + 'Y', }; ble.clearAdvertisingPayload(); @@ -106,8 +437,14 @@ ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); ble.setAdvertisingInterval(1600); /* 1s; in multiples of 0.625ms. */ ble.startAdvertising(); + + osjob_t initjob; - while (true) { - ble.waitForEvent(); - } + // initialize runtime env + os_init( ); + // setup initial job + os_setCallback( &initjob, onInit ); + // execute scheduled jobs and events + os_runloop( ); + // (not reached) }