This is a simple program to work with RedBearLab BLE Controller App. Type something from the Terminal to send to the BLEController App or vice verse. Characteristics received from App will print on Terminal. This version works on the first hw version of the BLE Nano (1)

Dependencies:   BLE_API mbed nRF51822

Fork of nRF51822_SimpleChat by RedBearLab

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002 
00003 Copyright (c) 2012-2014 RedBearLab
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00006 and associated documentation files (the "Software"), to deal in the Software without restriction, 
00007 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
00008 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
00009 subject to the following conditions:
00010 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
00011 
00012 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
00013 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
00014 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
00015 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
00016 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 
00018 */
00019 
00020 /*
00021  *    The application works with the BLEController iOS/Android App.
00022  *    Type something from the Terminal to send
00023  *    to the BLEController App or vice verse.
00024  *    Characteristics received from App will print on Terminal.
00025  */
00026  
00027 #include "mbed.h"
00028 #include "ble/BLE.h"
00029 #include <myData.h>
00030 //#include "LocalFileSystem.h"
00031 
00032 #define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
00033 #define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
00034 #define BLE_UUIDS_RX_CHARACTERISTIC      0x0003 /**< The UUID of the RX Characteristic. */
00035 
00036 #define TXRX_BUF_LEN                     20
00037 
00038 BLE  ble;
00039 
00040 Serial pc(USBTX, USBRX);
00041 
00042 // The Nordic UART Service
00043 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00044 static const uint8_t uart_tx_uuid[]   = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00045 static const uint8_t uart_rx_uuid[]   = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00046 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
00047 
00048 static const int8_t txPower = 0xCD;
00049 
00050 uint8_t txPayload[TXRX_BUF_LEN] = {0,};
00051 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
00052 
00053 static uint8_t rx_buf[TXRX_BUF_LEN];
00054 static uint8_t rx_len=0;
00055 
00056 static uint32_t gTimeInstant = 5; // 1 second
00057 
00058 //LocalFileSystem local("local");
00059 
00060 static myData_t g_MyData[MAXBUFFER];
00061 
00062 uint16_t g_MyDataIdx=0;
00063 
00064 //uint8_t infoCollector[TXRX_BUF_LEN][10];
00065 
00066 DigitalOut led(LED1);
00067 PwmOut buzzer(p15);
00068 
00069 AnalogIn VP3(A3);
00070 AnalogIn VP4(A4);
00071 AnalogIn VP5(A5);
00072 
00073 Timeout timeout_err; // timeout for buzz on error
00074 Ticker periodicActions, eachInstant; 
00075 
00076 mtime_manager_t g_myTimeVar;
00077 mdate_manager_t g_myDateVar;
00078 
00079 InterruptIn event(p7);
00080 
00081 GattCharacteristic  txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
00082                                       
00083 GattCharacteristic  rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
00084                                       
00085 GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};
00086 
00087 GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
00088 
00089 
00090 //extern bool isInputValid(uint8_t * buffer);
00091 
00092 bool isInputValid(uint8_t * buffer){
00093     bool retValue=  false;
00094     
00095     switch (buffer[0]){
00096         case 'i':
00097             switch (buffer[1]){
00098                 case '3':
00099                 case '4':
00100                 case '5':
00101                     retValue = true;
00102                     break;
00103                 default:
00104                     retValue = false;    
00105             }
00106             break;
00107         case 'l':
00108             retValue = true;
00109             break;
00110         case 's':
00111             if (((buffer[1]>'9')||(buffer[1]<'0'))||((buffer[2]>'9')||(buffer[2]<'0')))
00112                 retValue = false;
00113             else 
00114                 retValue = true;
00115             break;    
00116         case 't': //timestamp 
00117             retValue = true;
00118             break;
00119         case 'd': //date
00120             retValue= true;
00121             break;    
00122         default:
00123             // error        
00124             retValue = false;
00125     }
00126     return retValue;
00127 }
00128 
00129 
00130 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
00131 {
00132     pc.printf("Disconnected \r\n");
00133     pc.printf("Restart advertising \r\n");
00134     ble.startAdvertising();
00135 }
00136 
00137 void buzz_int(uint8_t period, uint8_t duty_cycle){
00138     if (period!=0) {        
00139         buzzer = (9.0 - (float)duty_cycle)/9.0;
00140         buzzer.period((float)period);
00141     } else {
00142         buzzer = 0;
00143     }
00144 }
00145 
00146 float readInput_f(uint8_t channelID){
00147     float retVal=0.0;
00148     switch (channelID){
00149         case 3:
00150             retVal = VP3.read();
00151             break;
00152         case 4:
00153             retVal = VP4.read();
00154             break;
00155         case 5:
00156             retVal = VP5.read();
00157             break;    
00158     }
00159     return ((retVal*3.3));
00160 }
00161 
00162 void at_timeout_err(){
00163     // stop buzz
00164     buzz_int(0,0);
00165 }
00166 
00167 
00168 void at_eachInstant(){
00169     //static uint32_t counter = 0;
00170     // update time
00171     if (g_myTimeVar.updateTime ==false){
00172         g_myTimeVar.newTime.sec = (g_myTimeVar.currentTime.sec + gTimeInstant)% 60; 
00173         g_myTimeVar.newTime.min = (g_myTimeVar.currentTime.min + ((gTimeInstant + g_myTimeVar.currentTime.sec) / 60))%60;
00174         if (g_myTimeVar.newTime.min< g_myTimeVar.currentTime.min ) { 
00175             g_myTimeVar.currentTime.hour++;
00176         }
00177         g_myTimeVar.newTime.hour = (g_myTimeVar.currentTime.hour + (gTimeInstant / 3600+g_myTimeVar.newTime.min/60))%24;
00178         if (g_myTimeVar.newTime.hour < g_myTimeVar.currentTime.hour){
00179             g_myDateVar.newDate.day = (g_myDateVar.currentDate.day + 1)%(eNrDaysPerMonth[g_myDateVar.currentDate.month]+1);
00180             if (g_myDateVar.newDate.day < g_myDateVar.currentDate.day ){
00181                 g_myDateVar.newDate.month = (g_myDateVar.currentDate.month+ 1)%13+1;
00182                 if (g_myDateVar.newDate.month< g_myDateVar.currentDate.month){
00183                     g_myDateVar.newDate.year = (g_myDateVar.currentDate.year+ 1);
00184                 }
00185             }
00186            memcpy(&g_myDateVar.currentDate,&g_myDateVar.newDate, sizeof(date_t));
00187         }
00188         memcpy(&g_myTimeVar.currentTime,&g_myTimeVar.newTime, sizeof(mtime_t));    
00189     } else {
00190         memcpy(&g_myTimeVar.currentTime,&g_myTimeVar.newTime, sizeof(mtime_t));    
00191         g_myTimeVar.updateTime =false;
00192     }
00193     if (g_myDateVar.updateDate ==true){  // there is a new Date ?
00194         memcpy(&g_myDateVar.currentDate,&g_myDateVar.newDate, sizeof(date_t));
00195         g_myDateVar.updateDate =true;
00196     }    
00197     
00198     // save some data
00199     memcpy(&g_MyData[g_MyDataIdx].date,&g_myDateVar.currentDate, sizeof(date_t));
00200     memcpy(&g_MyData[g_MyDataIdx].time,&g_myTimeVar.currentTime, sizeof(mtime_t));
00201     g_MyData[g_MyDataIdx].light = readInput_f(3);
00202     g_MyData[g_MyDataIdx].gndV = readInput_f(5);
00203     g_MyData[g_MyDataIdx].temp = readInput_f(4);
00204     g_MyData[g_MyDataIdx].led_on = led;
00205     
00206     /*
00207     int i=0;
00208     char buf[45];
00209     if (g_MyDataIdx==MAXBUFFER-1){
00210         // write2File
00211         FILE *fp = fopen("out.txt","a+");
00212         for (i=0;i<MAXBUFFER;i++){
00213             sprintf(buf,"20%2d-%2d-%2d %2d:%2d:%2d %4.3f %4.3f %4.3f %2d \r\n",g_MyData[i].date.year,
00214             g_MyData[i].date.month,g_MyData[i].date.day, g_MyData[i].time.hour, g_MyData[i].time.min, 
00215             g_MyData[i].time.sec, g_MyData[i].light, g_MyData[i].gndV, g_MyData[i].temp, g_MyData[i].led_on);
00216             fwrite(buf,sizeof(uint8_t),strlen(buf),fp);
00217         }
00218         fclose(fp);
00219         
00220     }*/
00221     g_MyDataIdx = (g_MyDataIdx+1)%MAXBUFFER;
00222 }
00223 /*
00224 void at_periodicActions(){
00225     char myBuf[TXRX_BUF_LEN]; 
00226     int index=0, length;
00227     float value[3];
00228        
00229     value[0] = readInput_f(3);
00230     value[1] = readInput_f(4);    
00231     sprintf(myBuf,">I3:%4.3f;I4:%4.3f",value[0],value[1]);
00232     length =18;
00233     memcpy(&infoCollector[0][index],&myBuf,length);    
00234     ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
00235     wait(0.3);
00236     
00237     index ++;
00238     value[2] = readInput_f(5);
00239     sprintf(myBuf,">I5:%4.3f;",value[2]);    
00240     length= 10;
00241     memcpy(&infoCollector[0][index],&myBuf,length);
00242     ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
00243     wait(0.3);
00244     index ++;
00245     length = 9;
00246     if (led==0){
00247         sprintf(myBuf,"%s",">LED: ON");
00248         memcpy(&infoCollector[0][index],&myBuf,length);
00249     }
00250     else {
00251         sprintf(myBuf,"%s",">LED:OFF");
00252         memcpy(&infoCollector[0][index],&myBuf,length);
00253     }
00254     ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &infoCollector[0][index], length); 
00255     wait(0.3);
00256 }
00257 */
00258 int decode(uint8_t * buffer, uint16_t* length){
00259 
00260     int retVal = 0;
00261     char myBuf[TXRX_BUF_LEN+1];    
00262     float value;
00263     
00264     buffer[0]=buffer[3];
00265     buffer[1]=' ';
00266     buffer[2]=':';
00267         switch (buffer[3]){
00268             case 'i': // Analog Input Read Request                
00269                     buffer[1]=buffer[4];                
00270                     if (isInputValid(&buffer[3])){
00271                         value = readInput_f((buffer[4]-'0'));                    
00272                         sprintf(myBuf,"%f",value);
00273                         memcpy(&buffer[3],&myBuf,7);   // e.g. 3.12345         
00274                         *length= 7+3;
00275                         }
00276                     else {                    
00277                         retVal= -1;                   
00278                     }
00279                 break;   
00280             case 'l': // toogle led
00281                 led = ! led;
00282                 if (led==0){
00283                     sprintf(myBuf,"%s","ON");
00284                     memcpy(&buffer[3],&myBuf,2);
00285                 }
00286                 else {
00287                     sprintf(myBuf,"%s","OFF");
00288                     memcpy(&buffer[3],&myBuf,3);
00289                 }
00290                 *length = 3 + 3;
00291                 break;
00292             case 's': // buzzer
00293                 buffer[1]=buffer[4];                
00294                 if (isInputValid(&buffer[3])){
00295                     buzz_int((buffer[4]-'0'),(buffer[5]-'0'));
00296                     buffer[2]=buffer[5];
00297                     sprintf(myBuf,"%s:%f","S",buzzer.read());
00298                     memcpy(&buffer[3],&myBuf,7);                
00299                     *length= 7+3;                    
00300                     retVal= 1;
00301                     }
00302                 else {                    
00303                     retVal= -1;                   
00304                 }
00305                 break;    
00306             case 't': // time operations
00307                 buffer[1]=buffer[4];
00308                 retVal=1;
00309                 switch (buffer[1]){
00310                     case 'i':  // time insert
00311                         memcpy(myBuf,&buffer[5],2);
00312                         g_myTimeVar.newTime.hour=atoi(myBuf); // TODO check if it is a number
00313                         memcpy(myBuf,&buffer[7],2);
00314                         g_myTimeVar.newTime.min=atoi(myBuf); // TODO check if it is a number
00315                         memcpy(myBuf,&buffer[9],2);
00316                         g_myTimeVar.newTime.sec=atoi(myBuf); // TODO check if it is a number
00317                         g_myTimeVar.updateTime = true;
00318                         *length = 3+2;
00319                         break;
00320                     case 'g':  // time get
00321                         sprintf(myBuf,"H:%2d:%2d:%2d",g_myTimeVar.currentTime.hour,g_myTimeVar.currentTime.min,g_myTimeVar.currentTime.sec);
00322                         memcpy(&buffer[3],myBuf,11);
00323                         *length = 3+11;
00324                         break;
00325                     default:     
00326                         retVal = -1; //error
00327                 }
00328                 break;       
00329              case 'd': // date operations
00330                 buffer[1]=buffer[4];
00331                 retVal=1;
00332                 switch (buffer[1]){
00333                     case 'i':  // date insert
00334                         memcpy(myBuf,&buffer[5],2);
00335                         g_myDateVar.newDate.year=atoi(myBuf); // TODO check if it is a number
00336                         memcpy(myBuf,&buffer[7],2);
00337                         g_myDateVar.newDate.month=atoi(myBuf); // TODO check if it is a number
00338                         memcpy(myBuf,&buffer[9],2);
00339                         g_myDateVar.newDate.day=atoi(myBuf); // TODO check if it is a number
00340                         g_myDateVar.updateDate = true;
00341                         *length = 3+2;
00342                         break;
00343                     case 'g':  // time get
00344                         sprintf(myBuf,"D:20%2d:%2d:%2d",g_myDateVar.currentDate.year,g_myDateVar.currentDate.month,g_myDateVar.currentDate.day);
00345                         memcpy(&buffer[3],myBuf,13);
00346                         *length = 3+13;
00347                         break;
00348                     default:     
00349                         retVal = -1; //error
00350                 }
00351                 break;          
00352             default:
00353                 retVal = -1;
00354         }
00355         if (retVal == -1){
00356             sprintf(myBuf,"%s","Incorect");
00357             memcpy(&buffer[3],&myBuf,8);
00358             *length= 8+3;
00359             buzz_int(5,3);
00360             timeout_err.attach(&at_timeout_err, 2);    
00361         }
00362         return retVal;
00363 }
00364 void WrittenHandler(const GattWriteCallbackParams *Handler)
00365 {   
00366     uint8_t buf[TXRX_BUF_LEN+1];    
00367     uint16_t bytesRead, index;
00368     
00369     if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) 
00370     {
00371         ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), &buf[2], &bytesRead);
00372         memset(txPayload, 0, TXRX_BUF_LEN);
00373         memcpy(txPayload, &buf[2], TXRX_BUF_LEN);       
00374         if (buf[2] == 'x'){
00375             decode(buf,&bytesRead);
00376         } else {
00377             //echo back
00378                 buf[0]='R';
00379                 buf[1]=':';                
00380                 bytesRead+=2;
00381         }        
00382         ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead); 
00383         // print on PC monitor
00384         //pc.printf("WriteHandler \r\n");
00385         //pc.printf("Length: %d \r\n", bytesRead);
00386         pc.printf("R: ");
00387         for(index=0; index<bytesRead; index++)
00388         {
00389             pc.putc(txPayload[index]);        
00390         }
00391         pc.printf("\r\n");       
00392         
00393     }
00394 }
00395 
00396 void uartCB(void)
00397 {   
00398     while(pc.readable())    
00399     {
00400         rx_buf[rx_len++] = pc.getc();    
00401         if(rx_len>=20 || rx_buf[rx_len-1]=='\0' || rx_buf[rx_len-1]=='\n')
00402         {            
00403             ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), rx_buf, rx_len);             
00404             //pc.printf("Rec: Length: %d \r\n",rx_len);                        
00405             rx_len = 2;
00406             rx_buf[0]='S';
00407             rx_buf[1]=':';
00408             break;
00409         }
00410     }
00411 }
00412 
00413 void button(){
00414     uint8_t buf[TXRX_BUF_LEN+1];
00415     buf[0]='B';
00416     buf[1]=':';
00417     buf[2]='O';
00418     buf[3]='N';
00419     ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4); 
00420 }
00421 
00422 void g_varInit(){
00423     g_myTimeVar.currentTime = (mtime_t){0,0,0};
00424     g_myTimeVar.updateTime = false;
00425     g_myDateVar.currentDate =(date_t){3,10,16};
00426     g_myDateVar.updateDate = false;
00427 }
00428 
00429 
00430 int main(void)
00431 {
00432     ble.init();
00433     ble.onDisconnection(disconnectionCallback);
00434     ble.onDataWritten(WrittenHandler);  
00435     event.rise(&button);
00436     periodicActions.attach(&at_eachInstant,gTimeInstant); // each second    
00437     pc.baud(19200);
00438     pc.printf("SimpleChat Init \r\n");
00439     g_varInit();
00440     
00441     pc.attach( uartCB , pc.RxIrq);
00442    // setup advertising 
00443     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
00444     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00445     ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
00446                                     (const uint8_t *)"MyBleVT", sizeof("MyBleVT") - 1);
00447     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
00448                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
00449     //ble.accumulateAdvertisingPayload(GapAdvertisingData::TX_POWER_LEVEL,(const uint8_t *)txPower, sizeof(txPower)); 
00450     ble.setTxPower(txPower);                                                                       
00451     // 100ms; in multiples of 0.625ms. 
00452     ble.setAdvertisingInterval(160);
00453 
00454     ble.addService(uartService);
00455     
00456     ble.startAdvertising(); 
00457     pc.printf("Advertising Start \r\n");
00458     
00459     while(1)
00460     {
00461         ble.waitForEvent(); 
00462     }
00463 }