Modified BLE_HeartRate Example Simple CHat code added

Dependencies:   BLE_API mbed nRF51822 X_NUCLEO_IDB0XA1

Fork of BLE_HeartRate by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 
00018 #include "mbed.h"
00019 #include "ble/BLE.h"
00020 #include "ble/services/HeartRateService.h"
00021 #include "ble/services/BatteryService.h"
00022 #include "ble/services/DeviceInformationService.h"
00023 #include "ble/services/UARTService.h"               // Not explictly used, I have just added this in.
00024 
00025 //** From Simple Chat example **//
00026 #define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
00027 #define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
00028 #define BLE_UUIDS_RX_CHARACTERISTIC      0x0003 /**< The UUID of the RX Characteristic. */
00029 
00030 #define TXRX_BUF_LEN                     20
00031 
00032  /* SimpleChat */ BLE  ble; // Commented out to prevent conflict
00033  /* HeartRate */ /* BLE &ble = params->ble; // Defined in scope of "bleInitComplete"
00034                   * ble_error_t error = params->error; */
00035                   
00036 Serial pc(USBTX, USBRX); // USBTX, USBRX origin unclear
00037 
00038 // The Nordic UART Service
00039 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00040 static const uint8_t uart_tx_uuid[]   = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00041 static const uint8_t uart_rx_uuid[]   = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
00042 static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
00043 
00044 uint8_t txPayload[TXRX_BUF_LEN] = {0,};
00045 uint8_t rxPayload[TXRX_BUF_LEN] = {0,};
00046 
00047 static uint8_t rx_buf[TXRX_BUF_LEN];
00048 static uint8_t rx_len=0;
00049 
00050 GattCharacteristic  txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
00051 GattCharacteristic  rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
00052 GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};
00053 GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
00054 
00055 void WrittenHandler(const GattWriteCallbackParams *Handler)
00056 {   
00057     uint8_t buf[TXRX_BUF_LEN];
00058     uint16_t bytesRead, index;
00059     
00060     if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) 
00061     {
00062         ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
00063         memset(txPayload, 0, TXRX_BUF_LEN);
00064         memcpy(txPayload, buf, TXRX_BUF_LEN);       
00065         pc.printf("WriteHandler \r\n");
00066         pc.printf("Length: ");
00067         pc.putc(bytesRead);
00068         pc.printf("\r\n");
00069         pc.printf("Data: ");
00070         for(index=0; index<bytesRead; index++)
00071         {
00072             pc.putc(txPayload[index]);        
00073         }
00074         pc.printf("\r\n");
00075     }
00076 }
00077 
00078 void uartCB(void)
00079 {   
00080     while(pc.readable())    
00081     {
00082         rx_buf[rx_len++] = pc.getc();    
00083         if(rx_len>=20 || rx_buf[rx_len-1]=='\0' || rx_buf[rx_len-1]=='\n')
00084         {
00085             ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), rx_buf, rx_len); 
00086             pc.printf("RecHandler \r\n");
00087             pc.printf("Length: ");
00088             pc.putc(rx_len);
00089             pc.printf("\r\n");
00090             rx_len = 0;
00091             break;
00092         }
00093     }
00094 }
00095 //** From Heart Rate example **//
00096 DigitalOut led1(LED1);
00097 
00098 const static char     DEVICE_NAME[]        = "Unudge_Prototype";
00099 static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE,
00100                                               GattService::UUID_DEVICE_INFORMATION_SERVICE};
00101 
00102 // Alternately to include the UART , I could use a different unit size ("uint128_list[]" rather than "uuid16_list[]")
00103 
00104 static volatile bool  triggerSensorPolling = false;
00105 
00106 uint8_t hrmCounter = 100; // init HRM to 100bps
00107 
00108 // These services are classes: "HeartRateService" and "DeviceInformationService" are defined in the BLE_API library under classes
00109 // The names of the objects are brought in as pointers
00110 HeartRateService         *hrService;
00111 DeviceInformationService *deviceInfo;
00112 
00113 // Specifics not understood, purpose clear: When the device is disconnected,
00114 // start advertising again immediately
00115 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
00116 {
00117     BLE::Instance(BLE::DEFAULT_INSTANCE).startAdvertising(); // restart advertising
00118     // Alternate Content
00119     /*pc.printf("Disconnected \r\n");
00120     pc.printf("Restart advertising \r\n");
00121     ble.startAdvertising();*/
00122 }
00123 
00124 // This function switches the led ON/OFF and
00125 // sets a flag value which is used in int main ()
00126 void periodicCallback(void)
00127 {
00128     led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
00129 
00130     /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
00131      * heavy-weight sensor polling from the main thread. */
00132     triggerSensorPolling = true;
00133     
00134     // ".available" is guesswork. I need something to check
00135     // If there's any incoming message - onDataWritten?
00136     /*
00137     if(ble.getGapState().available) {
00138         // I anticipate using a single char input to flag
00139         // The intended purpose of the communication
00140         
00141         // read in "someFlag" and store
00142         string someFlag = /syntax for reading ble input/
00143         
00144         switch(someFlag){
00145             case 'S':
00146             inBoundSettingChange = true;
00147             break;
00148             case 'R':
00149             inBoundRhythm = true;
00150             break;
00151             default:
00152             break;
00153         }
00154         //Flush someFlag
00155         someFlag = '';
00156     }
00157     */
00158 }
00159 
00160 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
00161 {
00162     // BLE is the class, &ble is the address of the declared object
00163     // "params->" purpose unknown
00164     BLE &ble          = params->ble;
00165     ble_error_t error = params->error;
00166 
00167     if (error != BLE_ERROR_NONE) {
00168         return;
00169     }
00170 
00171     ble.onDisconnection(disconnectionCallback);
00172 
00173     /* Setup primary service. */
00174     hrService = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
00175 
00176     /* Setup auxiliary service. */
00177     // 2nd parameter - the manufacturer's name // rev - revision
00178     deviceInfo = new DeviceInformationService(ble, "ARM", "Model1", "SerialNo#", "hw-rev1", "fw-rev1", "soft-rev1");
00179 
00180     /* Setup advertising. */
00181     // This line below is mandatory for bluetooth smart
00182     // It indicates the device only supports Bluetooth Low Energy
00183     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00184     // I believe this advertises the service list
00185     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
00186     
00187     // I realise that this isn't efficient but I would rather keep the code as
00188     // Is for now, so that it actually works. Hence why a 2nd "COMPLETE_LIST"
00189     /* SimpleChat */ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
00190                      (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
00191     
00192     ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
00193     // Advertise the device name
00194     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
00195     // Appears in all examples I have seen
00196     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00197     
00198     // Setup Advertising Interval
00199     ble.setAdvertisingInterval(1000); /* 1000ms */
00200     
00201     /* SimpleChat */ ble.addService(uartService);
00202     // Start Advertising
00203     ble.startAdvertising();
00204     
00205     /* SimpleChat */ pc.printf("Advertising Start \r\n");
00206 }
00207 
00208 int main(void)
00209 {
00210     pc.baud(9600);
00211     pc.printf("Baud Rate set to 9600 \r\n");
00212     
00213     pc.attach( uartCB , pc.RxIrq);
00214     
00215     led1 = 1;
00216     Ticker ticker;
00217     ticker.attach(periodicCallback, 1); // blink LED every second
00218 
00219     BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
00220     ble.init(bleInitComplete);
00221 
00222     /* SpinWait for initialization to complete. This is necessary because the
00223      * BLE object is used in the main loop below. */
00224     while (ble.hasInitialized()  == false) { /* spin loop */ }
00225 
00226     /* SimpleChat */ // Places nothing in the while (1) {} loop
00227                      // It's relying on interrupts rather than
00228                      // a periodic callback via a Ticker
00229     // infinite loop
00230     while (1) {
00231         // check for trigger from periodicCallback()
00232         if (triggerSensorPolling && ble.getGapState().connected) {
00233             triggerSensorPolling = false;
00234 
00235             // Do blocking calls or whatever is necessary for sensor polling.
00236             // In our case, we simply update the HRM measurement.
00237             hrmCounter++;
00238             if (hrmCounter == 175) { //  100 <= HRM bps <=175
00239                 hrmCounter = 100;
00240             }
00241             hrService->updateHeartRate(hrmCounter);
00242         // Code relating to storing/playing inbound rhythm
00243         // Into "Rhythm" Class (Yet to be defined)
00244         /*} else if (inBoundRhythm && ble.getGapState().connected) {
00245             inBoundRhythm = false;
00246             Rhythm inRhythm;
00247             inRythm += syntax for getting the incoming string
00248             inRhythm.play(); // Create Member function which 
00249                              // Plays Rhythms
00250             
00251         */
00252         // Code relating to storing/sending outbound rhythm
00253         /*} else if (inBoundRhythm && ble.getGapState().connected) {
00254             inBoundRhythm = false;
00255             Rhythm inRhythm;
00256             inRythm += syntax for getting the incoming string
00257             inRhythm.play(); // Create Member function which 
00258                              // Plays Rhythms
00259             
00260         */
00261         
00262         // How will I set inBoundRhythm = true; ?
00263         } else {
00264             ble.waitForEvent(); // low power wait for event
00265         }
00266     }
00267 }