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:
8:f28ad4600b0f
Parent:
7:609dff35b660
Child:
9:303d3628986a
--- a/main.cpp	Thu Mar 31 16:36:01 2016 +0000
+++ b/main.cpp	Mon Apr 11 17:21:14 2016 +0000
@@ -26,7 +26,8 @@
  
 #include "mbed.h"
 #include "ble/BLE.h"
-
+#include <myData.h>
+//#include "LocalFileSystem.h"
 
 #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. */
@@ -38,14 +39,13 @@
 
 Serial pc(USBTX, USBRX);
 
-
 // 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};
 static const uint8_t uart_rx_uuid[]   = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
 
-uint16_t txPower = 0xCD;
+static const int8_t txPower = 0xCD;
 
 uint8_t txPayload[TXRX_BUF_LEN] = {0,};
 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
@@ -53,6 +53,30 @@
 static uint8_t rx_buf[TXRX_BUF_LEN];
 static uint8_t rx_len=0;
 
+static uint32_t gTimeInstant = 5; // 1 second
+
+//LocalFileSystem local("local");
+
+static myData_t g_MyData[MAXBUFFER];
+
+uint16_t g_MyDataIdx=0;
+
+//uint8_t infoCollector[TXRX_BUF_LEN][10];
+
+DigitalOut led(LED1);
+PwmOut buzzer(p15);
+
+AnalogIn VP3(A3);
+AnalogIn VP4(A4);
+AnalogIn VP5(A5);
+
+Timeout timeout_err; // timeout for buzz on error
+Ticker periodicActions, eachInstant; 
+
+mtime_manager_t g_myTimeVar;
+mdate_manager_t g_myDateVar;
+
+InterruptIn event(p7);
 
 GattCharacteristic  txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
                                       
@@ -63,6 +87,45 @@
 GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
 
 
+//extern bool isInputValid(uint8_t * buffer);
+
+bool isInputValid(uint8_t * buffer){
+    bool retValue=  false;
+    
+    switch (buffer[0]){
+        case 'i':
+            switch (buffer[1]){
+                case '3':
+                case '4':
+                case '5':
+                    retValue = true;
+                    break;
+                default:
+                    retValue = false;    
+            }
+            break;
+        case 'l':
+            retValue = true;
+            break;
+        case 's':
+            if (((buffer[1]>'9')||(buffer[1]<'0'))||((buffer[2]>'9')||(buffer[2]<'0')))
+                retValue = false;
+            else 
+                retValue = true;
+            break;    
+        case 't': //timestamp 
+            retValue = true;
+            break;
+        case 'd': //date
+            retValue= true;
+            break;    
+        default:
+            // error        
+            retValue = false;
+    }
+    return retValue;
+}
+
 
 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
 {
@@ -71,9 +134,236 @@
     ble.startAdvertising();
 }
 
+void buzz_int(uint8_t period, uint8_t duty_cycle){
+    if (period!=0) {        
+        buzzer = (9.0 - (float)duty_cycle)/9.0;
+        buzzer.period((float)period);
+    } else {
+        buzzer = 0;
+    }
+}
+
+float readInput_f(uint8_t channelID){
+    float retVal=0.0;
+    switch (channelID){
+        case 3:
+            retVal = VP3.read();
+            break;
+        case 4:
+            retVal = VP4.read();
+            break;
+        case 5:
+            retVal = VP5.read();
+            break;    
+    }
+    return ((retVal*3.3));
+}
+
+void at_timeout_err(){
+    // stop buzz
+    buzz_int(0,0);
+}
+
+
+void at_eachInstant(){
+    //static uint32_t counter = 0;
+    // update time
+    if (g_myTimeVar.updateTime ==false){
+        g_myTimeVar.newTime.sec = (g_myTimeVar.currentTime.sec + gTimeInstant)% 60; 
+        g_myTimeVar.newTime.min = (g_myTimeVar.currentTime.min + ((gTimeInstant + g_myTimeVar.currentTime.sec) / 60))%60;
+        if (g_myTimeVar.newTime.min< g_myTimeVar.currentTime.min ) { 
+            g_myTimeVar.currentTime.hour++;
+        }
+        g_myTimeVar.newTime.hour = (g_myTimeVar.currentTime.hour + (gTimeInstant / 3600+g_myTimeVar.newTime.min/60))%24;
+        if (g_myTimeVar.newTime.hour < g_myTimeVar.currentTime.hour){
+            g_myDateVar.newDate.day = (g_myDateVar.currentDate.day + 1)%(eNrDaysPerMonth[g_myDateVar.currentDate.month]+1);
+            if (g_myDateVar.newDate.day < g_myDateVar.currentDate.day ){
+                g_myDateVar.newDate.month = (g_myDateVar.currentDate.month+ 1)%13+1;
+                if (g_myDateVar.newDate.month< g_myDateVar.currentDate.month){
+                    g_myDateVar.newDate.year = (g_myDateVar.currentDate.year+ 1);
+                }
+            }
+           memcpy(&g_myDateVar.currentDate,&g_myDateVar.newDate, sizeof(date_t));
+        }
+        memcpy(&g_myTimeVar.currentTime,&g_myTimeVar.newTime, sizeof(mtime_t));    
+    } else {
+        memcpy(&g_myTimeVar.currentTime,&g_myTimeVar.newTime, sizeof(mtime_t));    
+        g_myTimeVar.updateTime =false;
+    }
+    if (g_myDateVar.updateDate ==true){  // there is a new Date ?
+        memcpy(&g_myDateVar.currentDate,&g_myDateVar.newDate, sizeof(date_t));
+        g_myDateVar.updateDate =true;
+    }    
+    
+    // save some data
+    memcpy(&g_MyData[g_MyDataIdx].date,&g_myDateVar.currentDate, sizeof(date_t));
+    memcpy(&g_MyData[g_MyDataIdx].time,&g_myTimeVar.currentTime, sizeof(mtime_t));
+    g_MyData[g_MyDataIdx].light = readInput_f(3);
+    g_MyData[g_MyDataIdx].gndV = readInput_f(5);
+    g_MyData[g_MyDataIdx].temp = readInput_f(4);
+    g_MyData[g_MyDataIdx].led_on = led;
+    
+    /*
+    int i=0;
+    char buf[45];
+    if (g_MyDataIdx==MAXBUFFER-1){
+        // write2File
+        FILE *fp = fopen("out.txt","a+");
+        for (i=0;i<MAXBUFFER;i++){
+            sprintf(buf,"20%2d-%2d-%2d %2d:%2d:%2d %4.3f %4.3f %4.3f %2d \r\n",g_MyData[i].date.year,
+            g_MyData[i].date.month,g_MyData[i].date.day, g_MyData[i].time.hour, g_MyData[i].time.min, 
+            g_MyData[i].time.sec, g_MyData[i].light, g_MyData[i].gndV, g_MyData[i].temp, g_MyData[i].led_on);
+            fwrite(buf,sizeof(uint8_t),strlen(buf),fp);
+        }
+        fclose(fp);
+        
+    }*/
+    g_MyDataIdx = (g_MyDataIdx+1)%MAXBUFFER;
+}
+/*
+void at_periodicActions(){
+    char myBuf[TXRX_BUF_LEN]; 
+    int index=0, length;
+    float value[3];
+       
+    value[0] = readInput_f(3);
+    value[1] = readInput_f(4);    
+    sprintf(myBuf,">I3:%4.3f;I4:%4.3f",value[0],value[1]);
+    length =18;
+    memcpy(&infoCollector[0][index],&myBuf,length);    
+    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
+    wait(0.3);
+    
+    index ++;
+    value[2] = readInput_f(5);
+    sprintf(myBuf,">I5:%4.3f;",value[2]);    
+    length= 10;
+    memcpy(&infoCollector[0][index],&myBuf,length);
+    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
+    wait(0.3);
+    index ++;
+    length = 9;
+    if (led==0){
+        sprintf(myBuf,"%s",">LED: ON");
+        memcpy(&infoCollector[0][index],&myBuf,length);
+    }
+    else {
+        sprintf(myBuf,"%s",">LED:OFF");
+        memcpy(&infoCollector[0][index],&myBuf,length);
+    }
+    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
+    wait(0.3);
+}
+*/
+int decode(uint8_t * buffer, uint16_t* length){
+
+    int retVal = 0;
+    char myBuf[TXRX_BUF_LEN+1];    
+    float value;
+    
+    buffer[0]=buffer[3];
+    buffer[1]=' ';
+    buffer[2]=':';
+        switch (buffer[3]){
+            case 'i': // Analog Input Read Request                
+                    buffer[1]=buffer[4];                
+                    if (isInputValid(&buffer[3])){
+                        value = readInput_f((buffer[4]-'0'));                    
+                        sprintf(myBuf,"%f",value);
+                        memcpy(&buffer[3],&myBuf,7);   // e.g. 3.12345         
+                        *length= 7+3;
+                        }
+                    else {                    
+                        retVal= -1;                   
+                    }
+                break;   
+            case 'l': // toogle led
+                led = ! led;
+                if (led==0){
+                    sprintf(myBuf,"%s","ON");
+                    memcpy(&buffer[3],&myBuf,2);
+                }
+                else {
+                    sprintf(myBuf,"%s","OFF");
+                    memcpy(&buffer[3],&myBuf,3);
+                }
+                *length = 3 + 3;
+                break;
+            case 's': // buzzer
+                buffer[1]=buffer[4];                
+                if (isInputValid(&buffer[3])){
+                    buzz_int((buffer[4]-'0'),(buffer[5]-'0'));
+                    buffer[2]=buffer[5];
+                    sprintf(myBuf,"%s:%f","S",buzzer.read());
+                    memcpy(&buffer[3],&myBuf,7);                
+                    *length= 7+3;                    
+                    retVal= 1;
+                    }
+                else {                    
+                    retVal= -1;                   
+                }
+                break;    
+            case 't': // time operations
+                buffer[1]=buffer[4];
+                retVal=1;
+                switch (buffer[1]){
+                    case 'i':  // time insert
+                        memcpy(myBuf,&buffer[5],2);
+                        g_myTimeVar.newTime.hour=atoi(myBuf); // TODO check if it is a number
+                        memcpy(myBuf,&buffer[7],2);
+                        g_myTimeVar.newTime.min=atoi(myBuf); // TODO check if it is a number
+                        memcpy(myBuf,&buffer[9],2);
+                        g_myTimeVar.newTime.sec=atoi(myBuf); // TODO check if it is a number
+                        g_myTimeVar.updateTime = true;
+                        *length = 3+2;
+                        break;
+                    case 'g':  // time get
+                        sprintf(myBuf,"H:%2d:%2d:%2d",g_myTimeVar.currentTime.hour,g_myTimeVar.currentTime.min,g_myTimeVar.currentTime.sec);
+                        memcpy(&buffer[3],myBuf,11);
+                        *length = 3+11;
+                        break;
+                    default:     
+                        retVal = -1; //error
+                }
+                break;       
+             case 'd': // date operations
+                buffer[1]=buffer[4];
+                retVal=1;
+                switch (buffer[1]){
+                    case 'i':  // date insert
+                        memcpy(myBuf,&buffer[5],2);
+                        g_myDateVar.newDate.year=atoi(myBuf); // TODO check if it is a number
+                        memcpy(myBuf,&buffer[7],2);
+                        g_myDateVar.newDate.month=atoi(myBuf); // TODO check if it is a number
+                        memcpy(myBuf,&buffer[9],2);
+                        g_myDateVar.newDate.day=atoi(myBuf); // TODO check if it is a number
+                        g_myDateVar.updateDate = true;
+                        *length = 3+2;
+                        break;
+                    case 'g':  // time get
+                        sprintf(myBuf,"D:20%2d:%2d:%2d",g_myDateVar.currentDate.year,g_myDateVar.currentDate.month,g_myDateVar.currentDate.day);
+                        memcpy(&buffer[3],myBuf,13);
+                        *length = 3+13;
+                        break;
+                    default:     
+                        retVal = -1; //error
+                }
+                break;          
+            default:
+                retVal = -1;
+        }
+        if (retVal == -1){
+            sprintf(myBuf,"%s","Incorect");
+            memcpy(&buffer[3],&myBuf,8);
+            *length= 8+3;
+            buzz_int(5,3);
+            timeout_err.attach(&at_timeout_err, 2);    
+        }
+        return retVal;
+}
 void WrittenHandler(const GattWriteCallbackParams *Handler)
 {   
-    uint8_t buf[TXRX_BUF_LEN+1];
+    uint8_t buf[TXRX_BUF_LEN+1];    
     uint16_t bytesRead, index;
     
     if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) 
@@ -81,10 +371,15 @@
         ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), &buf[2], &bytesRead);
         memset(txPayload, 0, TXRX_BUF_LEN);
         memcpy(txPayload, &buf[2], TXRX_BUF_LEN);       
-        //echo back
-        buf[0]='R';
-        buf[1]=':';
-        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead+2); 
+        if (buf[2] == 'x'){
+            decode(buf,&bytesRead);
+        } else {
+            //echo back
+                buf[0]='R';
+                buf[1]=':';                
+                bytesRead+=2;
+        }        
+        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead); 
         // print on PC monitor
         //pc.printf("WriteHandler \r\n");
         //pc.printf("Length: %d \r\n", bytesRead);
@@ -93,7 +388,8 @@
         {
             pc.putc(txPayload[index]);        
         }
-        pc.printf("\r\n");
+        pc.printf("\r\n");       
+        
     }
 }
 
@@ -114,14 +410,33 @@
     }
 }
 
+void button(){
+    uint8_t buf[TXRX_BUF_LEN+1];
+    buf[0]='B';
+    buf[1]=':';
+    buf[2]='O';
+    buf[3]='N';
+    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4); 
+}
+
+void g_varInit(){
+    g_myTimeVar.currentTime = (mtime_t){0,0,0};
+    g_myTimeVar.updateTime = false;
+    g_myDateVar.currentDate =(date_t){3,10,16};
+    g_myDateVar.updateDate = false;
+}
+
+
 int main(void)
 {
     ble.init();
     ble.onDisconnection(disconnectionCallback);
     ble.onDataWritten(WrittenHandler);  
-    
+    event.rise(&button);
+    periodicActions.attach(&at_eachInstant,gTimeInstant); // each second    
     pc.baud(19200);
     pc.printf("SimpleChat Init \r\n");
+    g_varInit();
     
     pc.attach( uartCB , pc.RxIrq);
    // setup advertising