Continuous Bluetooth LE data transfer to iPhone using the RedBear BLE shield

This is an update on our work on creating a bluetooth home health monitor in my class BME 440/441 "Senior Design in Biomedical Engineering".  The idea is to create an iPhone app that can connect to several Bluetooth LE sensors (ECG, EEG, Galvanic Skin response) and then display and record the data.  There will also be a data analysis component to actively monitor the health of the subject.

This post will describe a simple Arduino sketch that measures an analog signal at regular time intervals and then sends it through the Bluetooth connection of the RedBear BLE Shield. The sketch uses a timer to set the frequency at which analog pin 5 is measured and writes it into a buffer that is then sent through the BLE shield. I had to add a flag analog_enabled to make sure that the BLE shield only receives data when connected to the iPhone app. Unfortunately, there is a bug in the RedBear BLE shield software that makes it necessary to first receive data before it can send (I used BLE_Shield_Library 1.0). I could not get this project to work without the iPhone first sending at least one byte of data. In our case, when the iPhone sends "I" then the BLE shield starts sending. When the iPhone sends "0" then the BLE shield stops sending. I also included the parameters for 100Hz and 2Hz data transmissions.  Here is the sketch:

untitled
#include <SPI.h>
#include <ble.h>

#define ANALOG_IN_PIN      A5

boolean analog_enabled = false;

void setup()
{
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  SPI.begin();
  ble_begin();
  
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  
  //100 hz timer setup
  OCR1A = 2500;            // compare match register 16MHz/64/100Hz
  TCCR1B |= (1 << CS11) | (1 << CS10);    // 64 prescaler
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt 
  TCCR1B |= (1 << WGM12);   // CTC mode
  
  /*  
  //2 Hz Timer Setup
  OCR1A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  TCCR1B |= (1 << WGM12);   // CTC mode
  */
  interrupts();             // enable all interrupts   
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  if (analog_enabled)  // if connected
  {
    // Read and send out
    uint16_t value = analogRead(ANALOG_IN_PIN);
    ble_write(value >> 8);
    ble_write(value);
  }
}

void loop()
{
  while(ble_available())
  {
    // read out command and data
    byte data0 = ble_read();
    // if data is "I" then turn on transmission
    // if data is "0" then turn off transmission
    if (data0==0x49) {
       analog_enabled = true;
    }
    else if (data0==0x30) {
      analog_enabled = false;
    }
  }
  // Allow BLE Shield to send/receive data
  ble_do_events();
  if (!ble_connected()) {
    analog_enabled = false;
  }
}

Now to the iPhone app. It can be found here: http://github.com/hstrey/BLEShieldConnect

The entry screen is a table view that scans for BLE devices and add them to the table. I used the new iOS6 pull down to refresh method that is really neat. When you select any of the available BLE shields, a Bluetooth LE connection is established and a new screen appears that displays the RSSI, analog value, and number of bytes send.  The number of bytes send is a measure for how often the BLE shield sends the data that is accumulating in the arduino buffer.

firstscreen.jpg
secondscreen.jpg
thirdscreen.jpg

A few remarks about the BLE SDK 0.4 that RedBear provides.  I was not very happy about the object design.  The sdk provides a ble object that has a method to scan for Bluetooth devices but then you can only connect to one of those devices.  That did not really make sense in terms of object oriented design.  There should be a more general class that is used to scan and then there should be individual BLE devices that you can connect to and those will provide protocols to receive and send data.

The iPhone program is quite simple but there was one aspect of its design that I struggled with for a while.  When switching views I had to transfer the ble object between view controllers.  In the table view I use the ble object to find all BLE shields in the area.  When I select one, I need to connect and then define all the protocols in the next view which all happens in the ble object.  Because the data protocols of the ble object are needed in the data view controller I need to pass the ble object to the data view controller in the prepareForSeque method as such:

untitled
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"Show Bluetooth Data"]) {
        NSIndexPath *path = [self.tableView indexPathForSelectedRow];
        BSCViewController *s = segue.destinationViewController;
        s.ble=self.ble;
        s.path=path;
    }
}

In the data view controller I need to set myself as delegate and connect to the BLE device in viewDidLoad. When I return to the table view I need to disconnect and tell the Arduino to stop sending data. At first, I tried to set the ble delegate to nil but that was not necessary.

untitled
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.ble.delegate=self;
    [self.ble connectPeripheral:[self.ble.peripherals objectAtIndex:self.path.row]];
}
 
- (void) viewWillDisappear:(BOOL)animated
{
    NSLog(@"ViewController will disappear");
    if (self.ble.activePeripheral)
        if(self.ble.activePeripheral.isConnected)
        {
            //send BLE shield "0" to turn off transmission
            UInt8 buf[1] = {0x30};
             
            NSData *data = [[NSData alloc] initWithBytes:buf length:1];
            [self.ble write:data];
            // after that cancel connection
            [[self.ble CM] cancelPeripheralConnection:[self.ble activePeripheral]];
        }
}

Back in the table view controller I simply reconnect the ble.delegate to self. This is necessary since viewDidLoad will only be called once.

untitled
-(void)viewWillAppear:(BOOL)animated
{
    //reconnect delegate when coming back to table view
    self.ble.delegate = self;
}

Now lets talk about the performance. With this setup, I was able to send 100 data points (2 bytes each) per second easily to the iPhone. At 200 data points per second the buffer overflows and the BLE arduino sketch crashes. Believe it or not, the RedBear BLE Arduino library does not protect from buffer overflows. I am planning to do a similar test with Dr. Kroll's BLE Shield because for our project we need 200 data points per second per sensor.

Let me know if you have any questions.