PIR + LoRa

Dependencies:   BLE_API LMiC SX1276Lib mbed nRF51822 nrf51_rtc

Fork of BLE_PhysicalWeb by Bluetooth Low Energy

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)
 }