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
Diff: main.cpp
- 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(); + } } }