Examples

Note: This page is scheduled to be updated with more details and an index. :)

Note: All of this code can be accessed from within the Arduino IDE after you've imported the BLEduino library. If you havn't done so yet, follow these instructions.

Base

This is the bare minimum required to communicate with the BLEduino.

#include <BLEduino.h>

BLEduino BLE;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  Serial.begin(57600);
}

void loop(){

  if(BLE.available()){
    
    //Read packet
    BLEPacket packet = BLE.read();
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;

    //Do things with data.
    for(byte i = 0; i < length; i++){
      Serial.print( (char) data[i]);
    }
  }
}
            

Bridge A. Demo

Send commands to another BLEduino (using the phone as a hub).

//Send commands to another BLEduino (using the phone as a hub).
#include <BLEduino.h>

BLEduino BLE;       

//This is the name of this BLEduino
//Do not use 0xFF as the name.  It is reserved.
char my_name = 'A'; 

//This is the name of the BLEduino that I will send data to.
//Do not use 0xFF as the name.  It is reserved.
char friend_name = 'B'; 

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  BLE.sendData(BRIDGE_ID_SEND, my_name);

  Serial.begin(57600);

  while(!Serial){;} 
  Serial.println("BLEduino BLE Bridge Demo");
  Serial.println("0 : Toggle BLEduino-BLED On-Off");
  Serial.println("Add more commands here...\n");
}

void loop(){
  if(Serial.available()){ //read command from Serial port

    check_size();
    
   /*--------------------------------------------------
    Packet Structure for BLE Bridge data
    ||      0      |      0      | ... |     N-1     ||
    || Destination | Character 1 | ... | Character N ||

    N -> Max = 20
    Destination = friend_name
    ---------------------------------------------------*/

    byte length = 2;
    byte command[length]; //the max size of the command
    
    command[0] = friend_name;
    command[1] = Serial.read();

    BLE.sendData(BRIDGE_SEND, command, 2);

   Serial.print("Sent command: "); Serial.println((char)command[1]);
  }
}

void check_size(){
  if(Serial.available() > 1){
    Serial.flush();

    Serial.println("One command at a time.");
  }
}
            

Bridge B. Demo

Recieve commands to another BLEduino (using the phone as a hub).

//Recieve commands to another BLEduino (using the phone as a hub).
#include <BLEduino.h>

BLEduino BLE;    

//This is the name of this BLEduino
//Do not use 0xFF as the name.  It is reserved.
char my_name = 'B'; 

//This is the name of the BLEduino that I will send data to (and sends me data)
//Do not use 0xFF as the name.  It is reserved.
char friend_name = 'A'; 

boolean led_state; 

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  BLE.sendData(BRIDGE_ID_SEND, my_name);
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the BRIDGE pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(BRIDGE_READ)){ //Read command sent from other BLEduino using BLE Bridge
   
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(BRIDGE_READ);
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;

    /*-------------------------------------------------
    Packet Structure for BLE Bridge data
    ||      0      |      0      | ... |     N-1     ||
    || Destination | Character 1 | ... | Character N ||

    Destination = friend_name
    ---------------------------------------------------*/

    //uint8_t who_sent_this = data[0]; //not used here

    switch(data[1]){
      case '0':
        //toggle BLEduino LED 
        led_state ^= 1;
        pinMode(BLEDUINO_LED, OUTPUT);
        digitalWrite(BLEDUINO_LED, led_state);
      break;

      case '1':
      //Add more commands here.
      break;
    }
  }
}
		

Console Demo

Write and receive character strings

//Write and receive character strings to and from the BLEduino
#include <BLEduino.h>

BLEduino BLE;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  Serial.begin(57600);

  while(!Serial){;} //Wait for serial monitor to be opened 

  Serial.println("Console Test.  Write a message (up to 20 characters long) and press enter...");
}

void loop(){

  //Read message from BLEduino
  //Print in Serial Monitor

  //Using pipes is optional
  //This will return the number of packets available from the UART pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(UART_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(UART_READ);
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;
    
    /*-------------------------------------------------
    Packet Structure for Keyboard data
    ||      0      |      1      | ... |      N      ||
    || Character 0 | Character 1 | ... | Character N ||
    ---------------------------------------------------*/
    
    //Print each character
    for(int i = 0; i < length; i++){
      Serial.print((char)data[i]);
    }
    Serial.println(""); //Add new line.
  }
  
  //Send message to BLEduino
  if(Serial.available()){
    
    if(!check_size()){
      return;
    }

    byte length = Serial.available();
    byte message[20];

    for(int i = 0; i < length; i++){
      message[i] = Serial.read();
    }

    BLE.sendData(UART_SEND, message, length);

    Serial.println("Message Sent");
  }
}

bool check_size(){
  if(Serial.available() > 20){
    Serial.flush();

    Serial.println("Message can be 20 characters max.");
    
    return 0;
  }
  return 1;
}
            
		

Controller Demo

Use the BLEduino as an HID game contoller from your phone.

//Use the BLEduino as an HID game contoller from your phone.
#include <BLEduino.h>

BLEduino BLE;

//Keyboard keys to simulate. (Press "up" on app -> simulate KEY_UP_ARROW on computer)
char up = KEY_UP_ARROW;
char left = KEY_LEFT_ARROW;
char down = KEY_DOWN_ARROW;
char right = KEY_RIGHT_ARROW;

char x = 'w';
char y = 'a';
char b = 's';
char a = 'd';

char start = KEY_RETURN;
char select = KEY_RIGHT_SHIFT;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  Keyboard.begin();
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the CONTROLLER pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(CONTROLLER_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(CONTROLLER_READ);
    
    //Parse packet
    //uint8_t length = packet.length; //Not used here
    uint8_t * data = packet.data;
    
    /*--------------------------------------
    Packet Structure for Controller-1 data
    |   0    |   1   |
    | Button | State |
    ---------------------------------------*/

    byte button = data[0];
    byte button_state = data[1];
    byte joystick_state = data[2];

    switch(button){
      case 0: //Vertical Joystick
        if(joystick_state > 0x0D){
          handle_keyboard(0, up);
          handle_keyboard(1, down); 
        }
       
        else if(joystick_state < 0x0D) { 
          handle_keyboard(0, down);
          handle_keyboard(1, up); 
        }
        
        else { 
          handle_keyboard(0, down);
          handle_keyboard(0, up);
        }
      break;

      case 1: //Horizontal Joystick
        if(joystick_state > 0x0D){
          handle_keyboard(0, left);
          handle_keyboard(1, right); 
        }
       
        else if(joystick_state < 0x0D) { 
          handle_keyboard(0, right);
          handle_keyboard(1, left); 
        }
        
        else { 
          handle_keyboard(0, left);
          handle_keyboard(0, right);
        }
      break;
      //
      case 2: handle_keyboard(button_state, y); break;

      case 3: handle_keyboard(button_state, x); break;

      case 4: handle_keyboard(button_state, a); break;

      case 5: handle_keyboard(button_state, b); break;
      ///
      case 6: handle_keyboard(button_state, start); break;

      case 7: handle_keyboard(button_state, select); break;
    }
  }
}

void handle_keyboard(char _state, char key){
  if(_state == 1){
    Keyboard.press(key);
  }

  else{
    Keyboard.release(key);
  }
}
		

Firmata Demo

Control all BLEduino functions with the phone app

            	
//Control all BLEduino functions with the phone app
#include <BLEduino.h>

#define WRITE_DIGITAL 0
#define READ_DIGITAL 1
#define READ_ANALOG 2
#define WRITE_PWM 3

BLEduino BLE;       

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the FIRMATA pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(FIRMATA_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(FIRMATA_READ);
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;
    
    /*------------------------------------------------
    Packet Structure for Vehicle data
    ||     0    |      1    |      2    ||
    || Pin Num. | Pin State | Pin Value ||

    Pin States:
    0: Output
    1: Input
    2: Analog (input)
    3: PWM (output)

    4: Beginning of sequence
    5: End of sequence
    6: Delay in seconds
    7: Delay in minutes
    --------------------------------------------------*/

    uint8_t pin_num = data[0];
    uint8_t pin_state = data[1];
    uint8_t pin_value = data[2];

    switch(pin_state){
      case WRITE_DIGITAL:
        write_digital(pin_num, pin_value);
      break;

      case READ_DIGITAL:
        read_digital(pin_num);
      break;

      case WRITE_PWM:
        write_pwm(pin_num, pin_value);
      break;

      case READ_ANALOG:
        read_analog(pin_num);
      break;
    }
  }
}

void write_digital(uint8_t _pin_num, uint8_t _pin_value){
  pinMode(_pin_num, OUTPUT);
  digitalWrite(_pin_num, _pin_value);
}

void read_digital(uint8_t _pin_num){
  pinMode(_pin_num, INPUT);

  byte value[4];
  value[0] = _pin_num;
  value[1] = READ_DIGITAL;
  value[2] = 0;
  value[3] = digitalRead(_pin_num);

  BLE.sendData(FIRMATA_SEND, value, 4);
}

void write_pwm(uint8_t _pin_num, uint8_t _pin_value){
  pinMode(_pin_num, OUTPUT);
  analogWrite(_pin_num, _pin_value);
}

void read_analog(uint8_t _pin_num){
  pinMode(_pin_num, INPUT);
  int value = analogRead(_pin_num);

  if(value <= 255){ 
    uint8_t packet_to_send[3];
    packet_to_send[0] = _pin_num;
    packet_to_send[1] = READ_DIGITAL;
    packet_to_send[2] = value;

    BLE.sendData(FIRMATA_SEND, packet_to_send, 3);
  }
  else{
    uint8_t byte_one = (value & 0x0300) >> 8;
    uint8_t byte_two = value & 0xFF;

    uint8_t packet_to_send[4];
    packet_to_send[0] = _pin_num;
    packet_to_send[1] = READ_DIGITAL;
    packet_to_send[2] = byte_one;
    packet_to_send[3] = byte_two;

    BLE.sendData(FIRMATA_SEND, packet_to_send, 4);
  }
}

		

Keyboard Demo

Use the BLEduino as an HID keyboard that's controlled via the phone.

//Use the BLEduino as an HID keyboard that's controlled via the phone.
#include <BLEduino.h>

BLEduino BLE;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  Keyboard.begin();
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the UART pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(UART_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(UART_READ);
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;
    
    /*-------------------------------------------------
    Packet Structure for Keyboard data
    ||      0      |      1      | ... |      N      ||
    || Character 0 | Character 1 | ... | Character N ||
    --------------------------------------------------*/

    for(byte i = 0; i < length; i++){
      Keyboard.write(data[i]);
    }
  }
}
		

LCD Demo

Write strings on the phone and display them on an LCD screen connected to a BLEduino.

//Write strings on the phone and display them on an LCD screen connected to a BLEduino.
#include <BLEduino.h>
#include <LiquidCrystal.h>

#define STRING_START 0
#define STRING_PENDING 1
#define STRING_END 2

#define LCD_LINES 2
#define LCD_CHARACTERS 16

BLEduino BLE;
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

byte line = 0;
byte character = 0;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino
  
  lcd.begin(16, 2);
  lcd.print("Hello Universe");
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the UART pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(UART_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(UART_READ);
    
    //Parse packet
    byte length = packet.length;
    byte * data = packet.data;
    
    /*---------------------------------------------------
    Packet Structure for LCD data
    ||      0      |      1      | ... |       N       ||
    || Indentifier | Character 0 | ... | Character N-1 ||
    
    Identifier = 0, 1, 2 (beginning, pending, end)
    -----------------------------------------------------*/
    
    if(!(data[0] == STRING_PENDING || data[0] == STRING_END)){
      lcd.clear();
      line = 0;
      character = 0;
    }
    
    //Write message to LCD
    for(byte i = 1; i < length; i++){
      
      lcd.print((char) data[i]);
      character++;
      
      if(character == LCD_CHARACTERS){ 
        line++; 
        character = 0;
        lcd.setCursor(character, line);
      }
      
      if(line == LCD_LINES){
        line = 0;
        lcd.setCursor(character, line);
      }
    }
  }
}  
		

LED Demo

Control an LED connected to the BLEduino.

// Control an LED connected to the BLEduino.
#include <BLEduino.h>

BLEduino BLE;

byte relay_pin = 3;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

}

void loop(){

    //Using pipes is optional
    //This will return the number of packets available from the FIRMATA pipe
    //Using BLE.available() will return all data returned, regardless of pipe.
    if(BLE.available(FIRMATA_READ)){
    
        //Read packet
        //The parameter is also optional here.  
        //BLE.read() will return the last packet received, regardless of pipe.
        BLEPacket packet = BLE.read(FIRMATA_READ);

        //Parse packet
        //uint8_t length = packet.length; //not used here
        uint8_t * data = packet.data;
        
        /*------------------------------------
        Packet Structure for LED data
        ||    0    |     1    |      2    ||
        || LED Pin | Not Used | Pin State ||

        Using firmata pipe
        -------------------------------------*/

        //Parse LED data
        byte led_pin = data[0];
        byte led_state = data[2];

        pinMode(led_pin, OUTPUT);
        digitalWrite(led_pin, led_state);
    }
}          
		

Notification Demo

Recieve notifications on your phone when events happen with the BLEduino.

//Recieve notifications on your phone when events happen with the BLEduino.
#include <BLEduino.h>

#define WRITE_DIGITAL 0
#define READ_DIGITAL 1
#define WRITE_PWM 2
#define READ_ANALOG 3

BLEduino BLE;       

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino
  
  Serial.begin(57600);

  while(!Serial){;} //Waiting for arduino serial monitor to be opened
  
  Serial.println("Type notification here...");
}

void loop(){
  if(Serial.available()){

    unsigned char notification[20]; //the max size of the notification
    byte length = Serial.available();

    for(int i = 0; Serial.available(); i++){
      notification[i] = Serial.read();
    }
    //notification[length] = '\0';
    
   /*--------------------------------------------------
    Packet Structure for Notification data
    ||      0      |      1      | ... |      N      ||
    || Character 0 | Character 1 | ... | Character N ||

    N -> Max = 20
    Pipe: UART
    --------------------------------------------------*/

    BLE.sendData(NOTIFICATION_SEND, notification, length);
    Serial.println("Notification Sent");
  }
}
		

Relay Demo

Control a relay from your phone.

// Control a relay from your phone
#include <BLEduino.h>

BLEduino BLE;

byte relay_pin = 13;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino
  
  pinMode(relay_pin, OUTPUT);
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the FIRMATA pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(FIRMATA_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(FIRMATA_READ);
    
    //Parse packet
    uint8_t length = packet.length; //not used here
    uint8_t * data = packet.data;
    
    /*-------------------------------------------------
    Packet Structure for Relay data
    ||      0               |     1    |      2      ||
    || Relay Pin (Optional) | Not Used | Relay Value ||
    
    Relay pin is not used in this example.
    --------------------------------------------------*/
    
    //Change relay state
    digitalWrite(relay_pin, data[2]);
  }
}        
		

Sequencer Demo

Send a firmata command sequence to the BLEduino. A.K.A. The biggest most complex demo we've got.

//Sequencer Module Code
//Send a firmata command sequence to the BLEduino
#include <BLEduino.h>

#define WRITE_DIGITAL 0
#define READ_DIGITAL 1
#define READ_ANALOG 2
#define WRITE_PWM 3

#define SEQUENCE_START 4
#define SEQUENCE_END 5
#define DELAY_SECONDS 6
#define DELAY_MINUTES 7

BLEduino BLE; 

uint8_t sequence_array[21][3];
uint8_t last_packet;

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino

  Serial.begin(57600);
}

void loop(){

  //Using pipes is optional
  //This will return the number of packets available from the FIRMATA pipe
  //Using BLE.available() will the number of packets from all pipes.
  if(BLE.available(FIRMATA_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(FIRMATA_READ);
    
    //Parse packet
    //uint8_t length = packet.length;
    //uint8_t * data = packet.data;

    /*---------------------------------------------------
    Packet Structure for Vehicle data
    ||     0    |      1    |      2    |       3      ||
    || Pin Num. | Pin State | Pin Value | Value Analog ||

    Pin State:
    0: Output
    1: Input
    2: Analog (input)
    3: PWM (output)

    4: Beginning of sequence
    5: End of sequence
    6: Delay in seconds
    7: Delay in minutes
    ----------------------------------------------------*/

    if(packet.data[1] == SEQUENCE_START){ 

      //read all packets in sequence
      byte i = 0;
      while(packet.data[1] != SEQUENCE_END){
        
        //add them to the sequence array
        if(BLE.available()){

          packet = BLE.read();

          sequence_array[i][0] = packet.data[0];
          sequence_array[i][1] = packet.data[1];
          sequence_array[i][2] = packet.data[2];
          i++;
        }
      }
      last_packet = i;
    }
  }
  for(int j = 0; j < last_packet; j++){
    sequence(sequence_array[j]);
  }
}

void sequence(uint8_t * data){

  uint8_t pin_num = data[0];
  uint8_t pin_state = data[1];
  uint8_t pin_value = data[2];

  switch(pin_state){
    case WRITE_DIGITAL:
      write_digital(pin_num, pin_value);
    break;

    case READ_DIGITAL:
      read_digital(pin_num);
    break;

    case WRITE_PWM:
      write_pwm(pin_num, pin_value);
    break;

    case READ_ANALOG:
      read_analog(pin_num);
    break;

    ////

    case SEQUENCE_START:
      //in_sequence = true;
      return;
    break;

    case SEQUENCE_END:
      //in_sequence = false;
      return;
    break;

    case DELAY_SECONDS:
      delay(pin_value * 1000);
    break;

    case DELAY_MINUTES:
      delay(pin_value * 1000 * 60);
    break;
  }
}

void write_digital(uint8_t _pin_num, uint8_t _pin_value){
  pinMode(_pin_num, OUTPUT);
  digitalWrite(_pin_num, _pin_value);
}

void read_digital(uint8_t _pin_num){
  pinMode(_pin_num, INPUT);

  byte value[4];
  value[0] = _pin_num;
  value[1] = READ_DIGITAL;
  value[2] = 0;
  value[3] = digitalRead(_pin_num);

  BLE.sendData(FIRMATA_SEND, value, 4);
}

void write_pwm(uint8_t _pin_num, uint8_t _pin_value){
  pinMode(_pin_num, OUTPUT);
  analogWrite(_pin_num, _pin_value);
}

void read_analog(uint8_t _pin_num){
  pinMode(_pin_num, INPUT);
  int value = analogRead(_pin_num);

  if(value <= 255){ 
    uint8_t packet_to_send[3];
    packet_to_send[0] = _pin_num;
    packet_to_send[1] = READ_ANALOG;
    packet_to_send[2] = 0;
    packet_to_send[3] = value;

    BLE.sendData(FIRMATA_SEND, packet_to_send, 4);
  }
  else{
    uint8_t byte_one = (value & 0x0300) >> 8;
    uint8_t byte_two = value & 0xFF;

    uint8_t packet_to_send[4];
    packet_to_send[0] = _pin_num;
    packet_to_send[1] = READ_ANALOG;
    packet_to_send[2] = byte_one;
    packet_to_send[3] = byte_two;

    BLE.sendData(FIRMATA_SEND, packet_to_send, 4);
  }
}            
		

Vehicle Demo

Control an RC vehicle from your phone.

//Control an RC vehicle from your phone.
#include <BLEduino.h>

BLEduino BLE;       

#define SPEED_A 3  //PWM control for motor outputs 1 and 2 is on digital pin 3
#define SPEED_B BD11 //PWM control for motor outputs 3 and 4 is on digital pin 11
#define DIR_A BD12 //dir control for motor outputs 1 and 2 is on digital pin 12
#define DIR_B BD13 //dir control for motor outputs 3 and 4 is on digital pin 13
#define FORWARD 0
#define REVERSE 1

void setup(){
  BLE.begin(); //Initialize BLE object
  BLE.sendCommand(COMMAND_RESET); //Start advertising BLEduino
  
  Serial.begin(57600);
  
  pinMode(SPEED_A, OUTPUT);  //Set control pins to be outputs
  pinMode(SPEED_B, OUTPUT);
  pinMode(DIR_A, OUTPUT);
  pinMode(DIR_B, OUTPUT);
  
  // Initialize all pins as low:
  digitalWrite(SPEED_A, LOW);
  digitalWrite(SPEED_B, LOW);
  digitalWrite(DIR_A, LOW);
  digitalWrite(DIR_B, LOW);
}

void loop(){
  
  //Using pipes is optional
  //This will return the number of packets available from the VEHICLE pipe
  //Using BLE.available() will return all data returned, regardless of pipe.
  if(BLE.available(VEHICLE_READ)){
    
    //Read packet
    //The parameter is also optional here.  
    //BLE.read() will return the last packet received, regardless of pipe.
    BLEPacket packet = BLE.read(VEHICLE_READ);
    
    //Parse packet
    uint8_t length = packet.length;
    uint8_t * data = packet.data;
    
    /*-------------------------------------------------------------
    Packet Structure for Vehicle data
    ||     0    |  1  |   2  |   3   ||
    || Throttle | Yaw | Roll | Pitch ||

    We only need throttle and yaw for our example.
    All values are unsigned so 0 = min | 16 = neutral | 32 = max
    --------------------------------------------------------------*/

    int throttle = data[0] - 15;  //centralize values to 0
    int yaw = data[1] - 15;       //centralize values to 0
    //byte roll = data[2];        //not used
    //byte pitch = data[3];       //not used

    drive(throttle, yaw);
  }
}

void drive(int throttle, int yaw){
  int right_wheel = 0;
  int left_wheel = 0;
  int dir = 0; //Low = forward //High = reverse

  if(yaw > 0){ //steer right
    right_wheel = 127;

    if(throttle < 0){ //going forward
      left_wheel = 255;
      dir = FORWARD;
    }

    else if(throttle > 0){ //going in reverse
      left_wheel = 255;
      dir = REVERSE;
    }
    
    else if(throttle == 0){
      left_wheel = 0;
      right_wheel = 0;
    }
  }

  else if(yaw < 0){ //steer left
    left_wheel = 127;

    if(throttle < 0){ //going forward
      right_wheel = 255;
      dir = FORWARD;
    }

    else if(throttle > 0){ //going in reverse
      right_wheel = 255;
      dir = REVERSE;
    }
    
    else if(throttle == 0){
      left_wheel = 0;
      right_wheel = 0;
    }
  }
  
  else if(yaw == 0){
    if(throttle < 0){ //going forward
      right_wheel = 255;
      left_wheel = 255;
      dir = FORWARD;
    }

    else if(throttle > 0){ //going in reverse
      right_wheel = 255;
      left_wheel = 255;
      dir = REVERSE;
    }
    
    else if(throttle == 0){
      left_wheel = 0;
      right_wheel = 0;
    }
  }

  digitalWrite(DIR_A, dir);
  digitalWrite(DIR_B, dir);  
  
  analogWrite(SPEED_A, left_wheel);
  analogWrite(SPEED_B, right_wheel);
}