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
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 }
Generated on Mon Jul 18 2022 05:58:50 by 1.7.2