App for BLE Nano to monitor the power consumption for a specific location, by intercepting the led flashes of a standard power meter. It counts and log the flashes for each second. It works with RedBear App for smart phone (Simple Chat App).

Dependencies:   BLE_API lib_mma8451q mbed nRF51822

Fork of nRF51822_DataLogger_with_Chat by Valentin Tanasa

Revision:
12:27e9c3db28b9
Parent:
11:baafa4f7a15e
--- a/main.cpp	Fri May 06 18:14:18 2016 +0000
+++ b/main.cpp	Sun Aug 14 14:57:09 2016 +0000
@@ -32,6 +32,11 @@
 #include <Gap.h>
 //#include "ble_flash.h"
 #include "ble_flash.c"
+#include "BatteryService.h"
+//#include "DFUService.h"
+
+BLE ble;
+//DFUService dfu(ble);
 
 #define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
 #define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
@@ -41,10 +46,15 @@
 
 #define MyASSERT(cond , serialpc, errVal) assert_error_app((bool)cond, serialpc, (uint16_t)errVal, __LINE__, __FILE__)
 
-BLE  ble;
 
 Serial pc(USBTX, USBRX);
 
+//uint8_t batteryLevel=100;
+uint16_t nr_of_hits = 0;
+uint32_t g_nrOfHits=0;
+float gmaxV=0,gminV=3,gmedianV=0.18; // Voltage of the PhotoResistorstatic float measure: max, min, median;
+
+bool bTimeReady = false;
 // The Nordic UART Service
 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
 static const uint8_t uart_tx_uuid[]   = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
@@ -52,8 +62,10 @@
 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
 
 static const int8_t txPower = 0xCD;
+//BatteryService *batteryService = NULL;
 
-uint8_t txPayload[TXRX_BUF_LEN] = {0, p28};
+//uint8_t txPayload[TXRX_BUF_LEN] = {0, p28};
+uint8_t txPayload[TXRX_BUF_LEN] = {0,};
 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
 
 static uint8_t rx_buf[TXRX_BUF_LEN];
@@ -61,29 +73,29 @@
 
 static uint32_t gTimeInstant = 1; // TimerTick Resolution, in seconds
 
+
 bool g_bIsConnected = false;
 bool g_bIsAdvertising = false;
 bool g_bConnDisabled = false;
-bool g_LogActive = false;
+bool g_LogActive = false;// g_bAccEnabled=false, g_bCalib = false;
 static myDataLog_t g_MyData;
 uint8_t g_MyDataIdx=0;
 
+
 // pins connected for measuring
-DigitalOut led(LED1);
-PwmOut buzzer(p15);
-InterruptIn event(p29); // button
-AnalogIn VP3(A3);
-AnalogIn VP4(A4);
-AnalogIn VP5(A5);
-AnalogIn* VP[3]= {&VP3,&VP4,&VP5};
-#define NUM_OF_READINGS (4u)
-myPayload_t g_currMeasures; // last measurements
+DigitalOut led(LED1), //redLed(D4);//, accBuzzAlarm(D3), accLEDAlarm(D5);
+
+//uint8_t tempAlarm, accAlarm;
+
+//PwmOut buzzer(D1); // changed from P15
+AnalogIn photoVoltage(A5); // photo voltaga measurement 
 
-Timeout timeout_err; // timeout for buzz on error
-Ticker periodicActions;
+myPayload_t g_currMeasures2; // last measurements
 
+//Timeout timeout_err; // timeout for buzz on error
+Ticker periodicActions, doMeasures;
 mdatetime_manager_t g_myDateTimeVar;
-
+//uint8_t gBatteryValue=0;
 GattCharacteristic  txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
 
 GattCharacteristic  rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
@@ -92,6 +104,15 @@
 
 GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
 
+void decode(uint8_t * buffer, uint16_t length);
+
+void alarm(){
+    
+    //accBuzzAlarm = 1;
+    //accLEDAlarm = 0;
+    //timeout_err.attach(&at_timeout_err, 2);
+}
+
 void sendRadioMsg(const uint8_t* buf, uint16_t length)
 {
     uint8_t retVal;
@@ -119,11 +140,6 @@
     g_bIsAdvertising = false;
 }
 
-void at_timeout_err()
-{
-    // stop buzz
-    buzz_int(&buzzer, 0,0);
-}
 void connectionUpdate(connection_update_t option)
 {
     if (g_bConnDisabled == false) {
@@ -158,9 +174,8 @@
         }
     }
 }
-void write_data_to_flash(uint32_t *tick)
+void write_data_to_flash(uint32_t *tick, myPayload_t * currMeasures)
 {
-    uint32_t retVal=0;
     uint8_t page_num=0;
 
     if (g_MyDataIdx==0) {
@@ -168,26 +183,29 @@
         connectionUpdate(eStartAdvertising);
         // time and date used to initialize the g_MyData variable
         memcpy(&g_MyData.startData.datetime,&g_myDateTimeVar.currentDateTime, sizeof(mdate_time_t));        
-        memcpy(&g_MyData.startData.data,&g_currMeasures, sizeof(myPayload_t));
+        memcpy(&g_MyData.startData.data,currMeasures, sizeof(myPayload_t));
     } else {
         // it should be logged here the time difference from last record...
         g_MyData.myData[g_MyDataIdx-1].minutes = (uint16_t)(*tick*gTimeInstant / 60);
         g_MyData.myData[g_MyDataIdx-1].seconds = (*tick*gTimeInstant% 60);
-        memcpy(&g_MyData.myData[g_MyDataIdx-1].data,&g_currMeasures, sizeof(myPayload_t));
+        memcpy(&g_MyData.myData[g_MyDataIdx-1].data,currMeasures, sizeof(myPayload_t));
     }
     *tick = 0;
 
-    if (g_MyDataIdx==(MAXBUFFER-5)) {
+    if (g_MyDataIdx==(MAXBUFFER-3)) {
         //initiate disconnection
         connectionUpdate(eDisconnect);
     }
 
     if (g_MyDataIdx == MAXBUFFER) {
         // write2Flash the current page num
+        //connectionUpdate(eDisconnect);
+        
         page_num=flash_currPage();
         // write2Flash the current page data
-        retVal=ble_flash_page_write(page_num, (uint32_t*)&(g_MyData), 251u);
-        pc.printf("retValWr: %d, Pg:%d, Min: %d \r\n",retVal, page_num,g_myDateTimeVar.currentDateTime.minutes);
+        ble_flash_page_write(page_num, (uint32_t*)&(g_MyData), 253);
+        memset(&g_MyData,0,sizeof(myDataLog_t));
+        //pc.printf("retValWr: %d, Pg:%d, Min: %d \r\n",retVal, page_num,g_myDateTimeVar.currentDateTime.minutes);
         flash_go_nextPage();
     }
     g_MyDataIdx = (g_MyDataIdx+1)%(MAXBUFFER+1);
@@ -197,10 +215,9 @@
 void on_error_radioMsg()
 {
     char myBuf[TXRX_BUF_LEN];
-
     sprintf(myBuf,"%s","WrongSyntax");
-    buzz_int(&buzzer,5,3);
-    timeout_err.attach(&at_timeout_err, 2);
+    //buzz_int(&buzzer,5,3);
+    //timeout_err.attach(&at_timeout_err, 2);
     sendRadioMsg((uint8_t*)&myBuf[0], 12);
 }
 
@@ -212,92 +229,184 @@
     uint8_t i;
 
     p_curr_addr += 2; // skip the magic number and the word count
-    memcpy((uint32_t*)&initialData, p_curr_addr, 6*sizeof(uint32_t));
+    memcpy((uint32_t*)&initialData, p_curr_addr, 3*sizeof(uint32_t));
     pdate = &initialData.startData.datetime;
     pc.printf("20%2d_%2d_%2d H:%2d P:%4x\r",pdate->year, pdate->month, pdate->day, pdate->hours, p_curr_addr);
-    pc.printf("%2d:%2d;%3d;%3d;%3d \r",pdate->minutes, pdate->seconds, initialData.startData.data.light, initialData.startData.data.gndV, initialData.startData.data.temp);
-    pc.printf("%2d:%2d;%3d;%3d;%3d;%2d\r",initialData.myData.minutes, initialData.myData.seconds, initialData.myData.data.light, initialData.myData.data.gndV, initialData.myData.data.temp);
-    p_curr_addr += 6;
+    pc.printf("%2d:%2d;%3d;%2d:%2d;%3d;\r",pdate->minutes, pdate->seconds, initialData.startData.data.hits,initialData.myData.minutes, initialData.myData.seconds, initialData.myData.data.hits);    
+    p_curr_addr += 3;
 
-    for (i=0; i<49; i++) {
-        memcpy((uint32_t*)&dataOut, p_curr_addr, 5*sizeof(uint32_t));
-        pc.printf("%2d:%2d;%3d;%3d;%3d;%2d\r",dataOut[0].minutes, dataOut[0].seconds, dataOut[0].data.light, dataOut[0].data.gndV, dataOut[0].data.temp, i);
-        pc.printf("%2d:%2d;%3d;%3d;%3d\r",dataOut[1].minutes, dataOut[1].seconds, dataOut[1].data.light, dataOut[1].data.gndV, dataOut[1].data.temp);
-        p_curr_addr += 5;
+    for (i=0; i<125; i++) {
+        memcpy((uint32_t*)&dataOut, p_curr_addr, 2*sizeof(uint32_t));
+        pc.printf("%2d:%2d;%3d;%2d:%2d;%3d;\r",dataOut[0].minutes, dataOut[0].seconds, dataOut[0].data.hits,dataOut[1].minutes, dataOut[1].seconds, dataOut[1].data.hits);        
+        p_curr_addr += 2;
     }
 }
 
-int update_measurements()
-{
-    int retVal;
-    static myPayload_t prevMeasures=(myPayload_t) {
-        0, 0, 0, 0, 0
-    };
+int sign(int nr){
+    int retVal=0;
+    if (nr>0) retVal=1;
+    else if (nr<0) retVal=-1;
+    
+    return retVal;    
+}
 
-    g_currMeasures = (myPayload_t) {
-        VP[0]->read_u16(), VP[2]->read_u16(), VP[1]->read_u16(), led, 0
-    };
-    retVal = memcmp(&g_currMeasures,&prevMeasures,sizeof(myPayload_t));
-    memcpy(&prevMeasures,&g_currMeasures,sizeof(myPayload_t));
-    return retVal;
+float read_real_value(void){
+    uint32_t wrk,reg0,reg1,reg2;
+    reg0 = NRF_ADC->ENABLE;     // save register value
+    reg1 = NRF_ADC->CONFIG;     // save register value
+    reg2 = NRF_ADC->RESULT;     // save register value
+    NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
+    NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
+                      (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
+                      (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
+                      (ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos) |
+                      (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
+    NRF_ADC->EVENTS_END  = 0;
+    NRF_ADC->TASKS_START = 1;
+    while (!NRF_ADC->EVENTS_END) {;}
+    wrk = NRF_ADC->RESULT;      // 10 bit result
+    NRF_ADC->ENABLE = reg0;     // recover register value
+    NRF_ADC->CONFIG = reg1;     // recover register value
+    NRF_ADC->RESULT = reg2;     // recover register value
+    NRF_ADC->EVENTS_END  = 0;
+    return ((float)wrk / 1024 * 1.2 * 3.0);            
 }
 
+uint8_t read100(void)
+{ 
+    float wrk_vdd, v0p= 2.7 ,v100p= 3.3;
+    wrk_vdd = read_real_value();
+    if (wrk_vdd <= v0p){
+        return 0;
+    } else if (wrk_vdd >= v100p){
+        led = 0;
+        return 100;
+        
+    }
+    led = 1;
+    wrk_vdd = (wrk_vdd - v0p) / (v100p - v0p);
+    return (uint8_t)(wrk_vdd * 100); 
+}
+
+
 void at_eachInstant()
 {
     static uint32_t tick=0;
-    int retVal;
+    static uint8_t ltick=0;
+    uint8_t rcBuff[2]={'r','0'};
+    //static myPayload_t prevMeasures2=(myPayload_t) { 0, 0, 0, 0};
 
     // update time
     update_time(&g_myDateTimeVar, gTimeInstant);
-
+   
+    //batteryService->updateBatteryLevel(gBatteryValue );
     //update measurements
-    retVal = update_measurements();
-
+    if (g_LogActive==true){       
     // if there are changes in data save
-    if ((retVal!=0)&&(g_LogActive==true)) {
-        write_data_to_flash(&tick);
+        if (0!=g_currMeasures2.hits){            
+            write_data_to_flash(&tick, &g_currMeasures2);                                   
+    }
+    if (g_bIsConnected == true){
+    // print info           
+        rcBuff[1]='0'+ltick;
+        decode(rcBuff,2);
+        ltick =(ltick+1)%4;
     }
     tick++;
+    
+    }
+}
+
+void update_measurements()
+{
+    nr_of_hits ++; 
+    g_nrOfHits ++;
+    /*if (bNewSample==false){ 
+        //g_currMeasures2.hits =nr_of_hits; 
+        nr_of_hits = 1;
+        bNewSample = true; 
+    } */   
+    
+    //gBatteryValue = read100();              
+    
+}
+
+void at_eachADC(){
+   static bool isLow = false;
+   static bool bPrevState=isLow;
+   static uint8_t counter = 0;
+   static float measure;
+   
+          
+   measure = photoVoltage.read();
+   if (g_LogActive==false){
+    if (measure > gmaxV) {
+       maxV=measure;
+    }
+    if (measure < minV) {
+        gminV=measure;
+    }    
+    //gmedian = gminV + (gminV + gmaxV)*10/4; % 25%
+   }
+   
+   isLow =  (measure < gmedianV);
+   if ((bPrevState != isLow)&&(isLow == true)){
+        nr_of_hits ++; 
+        g_nrOfHits ++;
+       }
+    bPrevState = isLow;
+   
+    counter = (counter + 1)%100;
+    if (counter==0){
+            // 1 second is passed
+            bTimeReady=true;
+            g_currMeasures2.hits =nr_of_hits; 
+            nr_of_hits = 0;
+        }
 }
 
 // Radio commands decode
 void decode(uint8_t * buffer, uint16_t length)
 {
+    char myBuf[TXRX_BUF_LEN];
     uint16_t len;
-    char myBuf[TXRX_BUF_LEN];
-
     switch (buffer[0]) {
-        case 'i': {// Analog Input Read Request
+        case 'r': {// Read Operations
             switch (buffer[1]) {
-                case '0': {
-                    // display all inputs
-                    sprintf(myBuf,"All:%3d,%3d,%3d,%2d", g_currMeasures.light,g_currMeasures.gndV,g_currMeasures.temp,g_currMeasures.led_on);
+                case '0':{
+                    sprintf(myBuf,"NH:%2d,TNH:%8d\r\n", g_currMeasures2.hits,g_nrOfHits);
+                    len = 19;
+                    break;
+                }
+                case '1':{
+                    sprintf(myBuf,"P:%1.2f_%1.2f_%1.2f\r\n", gmaxV,photoVoltage.read(),gminV);
                     len = 18;
                     break;
                 }
-                case '1': {
-                    sprintf(myBuf,"Input 1 = %3d", g_currMeasures.light);
-                    len = 13;
-                    break;
-                }
-                case '2': {
-                    sprintf(myBuf,"Input 2 = %3d", g_currMeasures.gndV);
-                    len = 13;
-                    break;
+                case '2':{
+                sprintf(myBuf,"g_idx=%2d Page=%3d",g_MyDataIdx, flash_currPage());
+                    len = 18;
+                    break;                    
                 }
                 case '3': {
-                    sprintf(myBuf,"Input 3 = %3d", g_currMeasures.temp);
-                    len = 13;
+                    sprintf(myBuf,"V:%2.3f\r\n", read_real_value());
+                    len = 11;
                     break;
                 }
                 case '4': {
-                    sprintf(myBuf,"Input 4 = %2d", g_currMeasures.led_on);
-                    len = 12;
+                    sprintf(myBuf,"PhVol:%2.2f,Av:%2.2f\r\n",photoVoltage.read(),gmedian);
+                    len = 20;
                     break;
                 }
-                default: {
-                    sprintf(myBuf,"All:%3d,%3d,%3d,%2d", g_currMeasures.light,g_currMeasures.gndV,g_currMeasures.temp,g_currMeasures.led_on);
-                    len = 18;
+                case '5': {
+                    //sprintf(myBuf,"Vmx_mn:%1.2f_%1.2f\r\n",maxV,minV);
+                    //len = 18;
+                    break;
+                }          
+                
+                default:{
+                    sprintf(myBuf,"Nothing \r\n");
+                    len = 10;
                     break;
                 }
             }
@@ -307,26 +416,27 @@
         case 'l': {// toogle led
             led = ! led;
             if (led==0) {
-                sprintf(myBuf,"%s","ON");
+                sprintf(myBuf,"%s","OFF");
                 len = 2;
             } else {
-                sprintf(myBuf,"%s","OFF");
+                sprintf(myBuf,"%s","ON");
                 len = 3;
             }
             sendRadioMsg((uint8_t *)myBuf, len);
             break;
-        }
-        case 's': {// buzzer
-            if (((buffer[1]>'9')||(buffer[1]<'0'))||((buffer[2]>'9')||(buffer[2]<'0'))) {
-                MyASSERT(true,&pc, buffer[1]); // notify on serial interface
-                on_error_radioMsg();  // notify on radio
-                break;
-            } else {
-                buzz_int(&buzzer, (buffer[1]-'0'),(buffer[2]-'0'));
-                sprintf(myBuf,"%s:%f","S",buzzer.read());
-                len= 7;
+        }        
+        case 'i':{ // Insert data values
+            switch (buffer[1]){
+                case 'm':{      // median change              
+                        memcpy(myBuf,&buffer[2],2);
+                        gmedian=(float)atoi(myBuf)/10; // TODO check if it is a number                                          
+                    break;
+                }
+                
+                default: {
+                   // on_error_radioMsg();  // notify on radio
+                }
             }
-            sendRadioMsg((uint8_t *)myBuf, len);
             break;
         }
         case 'd':
@@ -385,13 +495,25 @@
                     len = 12;
                     sendRadioMsg((uint8_t *)myBuf, len);
                     g_LogActive = true;
+                                      
                     break;
                 }
                 case '3': { // stop measuring
+                    doMeasures.detach();
                     sprintf(myBuf,"Stop Meas");
                     len = 11;
                     sendRadioMsg((uint8_t *)myBuf, len);
                     g_LogActive = false;
+                    ble_flash_page_write(flash_currPage(), (uint32_t*)&(g_MyData), 253);
+                    memset(&g_MyData,0,sizeof(myDataLog_t));
+                    flash_go_nextPage();
+                    break;
+                }
+                case '4':{ 
+                    break;
+                }
+                case '5':{ // read one measure
+                                    
                     break;
                 }
                 default: {
@@ -513,29 +635,6 @@
     }
 }
 
-void button()
-{
-    uint8_t buf[TXRX_BUF_LEN+1];
-    buf[0]='B';
-    buf[1]='U';
-    buf[2]='T';
-    buf[3]='N';
-    
-    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4);
-    g_bConnDisabled = !g_bConnDisabled;
-    led = !led;
-    if (g_bConnDisabled == true){
-        if (g_bIsConnected == true){
-            ble.disconnect((Gap::DisconnectionReason_t)0x12);
-            g_bIsConnected = false;
-        } else if (g_bIsAdvertising == true) {
-                ble.stopAdvertising();
-                g_bIsAdvertising = false;
-            }
-    } else {
-        connectionUpdate(eStartAdvertising);
-    }
-}
 
 void g_varInit()
 {
@@ -548,20 +647,24 @@
 {
     ble.init();
     g_varInit();
+    led= 1;
+    
     ble.onDisconnection(disconnectionCallback);
     ble.onConnection(connectionCallback);
     ble.onDataWritten(WrittenHandler);
-    event.rise(&button);
-
+    //event.rise(&button);
+    
+    
+    //event.rise(&accInt1);
     pc.baud(19200);
     pc.printf("SimpleChat Init \r\n");
-
+    
     pc.attach( uartCB , pc.RxIrq);
     // setup advertising
     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
     ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
-                                     (const uint8_t *)"MyBleVT", sizeof("MyBleVT") - 1);
+                                     (const uint8_t *)"CntBle3", sizeof("CntBle3") - 1);
     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                      (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
     //ble.accumulateAdvertisingPayload(GapAdvertisingData::TX_POWER_LEVEL,(const uint8_t *)txPower, sizeof(txPower));
@@ -576,10 +679,17 @@
     //ble.onRadioNotification(ptrFunc);
     */
     ble.addService(uartService);
+    //batteryService = new BatteryService(ble, batteryLevel);
     ble.startAdvertising();
-    pc.printf("Advertising Start \r\n");
-    periodicActions.attach(&at_eachInstant,gTimeInstant);
+    pc.printf("Advertising Start \r\n");   
+    //periodicActions.attach(&at_eachInstant,gTimeInstant);    
+    doMeasures.attach_us(&at_eachADC,10000);
+    //gBatteryValue = read100();
     while(1) {
         ble.waitForEvent();
+        if (bTimeReady==true){
+            bTimeReady=false;
+            at_eachInstant();
+        }
     }
 }