Android Bluetooth

The Ketai Bluetooth Class method onBluetoothDataEvent() does not work on the latest Android modes. Also, it has no readStringUntil() method which makes it difficult to read fast incoming data. So I wrote a native Android Bluetooth code to make this possible. I tested it on a MultiLaser Lollipop 5.1 device, as well as on a Samsung Android 10, using an HC-05 module set to a baud rate of 115200, without losing a single reading byte. The first code is the simplest reading code, it will display a single sine wave sent by the Arduino… The second, the simplest sending which will send a sine wave and can be seen in the serial plotter window of the Arduino IDE, The third is a combined code with two sliders that sent a frequency value to the Arduino which will generate two sine waves to be displayed on the device. You will need to give permissions “ACCESS_FINE_LOCATION” and “BLUETOOTH”.
If you use this code, please comment if it’s working or not.

Receiver
  • Arduino code
#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial mySerial(11, 12); // RX, TX
int data;
boolean toggle = false;

void setup() {
  mySerial.begin(115200); // Set the bluetooth model baudrate
  Serial.begin(115200); // Remember to set this plotter baudrate
}

void loop() {
  if (mySerial.available()) {
    data = mySerial.read();
    if(data > 254) toggle = true;
    if(data < 1) toggle = false;
    if (toggle)Serial.println(data);
    else Serial.println(data+255);
  }
}
  • Processing code
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 
import processing.core.PConstants;
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Activity activity;
Permission bt, afl;

Thread runThread;
byte[] readBuffer;
int buffer_index;
int counter;
boolean stop_thread, plotting = false, init = true;

String msg = " ";
String device_name = "HC-05";
String r_str = " ";
String t_str;
float px, py, x, y;

void setup() {
  fullScreen();
  orientation(LANDSCAPE);
  bt = new Permission(this, "BLUETOOTH");
  afl = new Permission(this, "ACCESS_FINE_LOCATION");
  textAlign(CENTER);
  textSize(70);
  t_str = "Click to connect.";
  textSize(12); // To create a "text width factor",
  float twf = width/textWidth(t_str);
  int f = 4; // Empericaly found 
  textSize(f*twf); // Making it  proportional for other screen resolutions
  activity = this.getActivity();
}

void draw() {
  if (plotting  == false && init) {
    background(150);
    text(t_str, width/2, height/2);
    strokeWeight(10);
    noFill();
    stroke(50);
    rect(0, 0, width, height);
  }
}

void mousePressed () {
  if (init) {
    try {
      init = false;
      findBluetooth();
      connect();
      plotting = true;
      fill(0, 0, 90);
      rect(0, 0, width, height); 
    } 
    catch (IOException ex) {
      println(ex);
    }
  }
}


void plot(String Str) {
  if (Str.length() < 3 || Str == null) Str =  "0#0";
  if (plotting) {
    stroke(0, 200, 255);
    strokeWeight(2);
    y = int(Str);
    int h = height/2;
    line(px, py+h, x, y+h);
    py = y;
    px = x;
    x++;
    if (x > width) {
      x = y = px = py = 0;
      background(0, 0, 90);
    }
  }
}

void findBluetooth() {
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
    println("No bluetooth adapter available");
  }
  if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(enableBluetooth, 0);
  }
  Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
    print("Paired devices MAC Adress:");
    printArray(pairedDevices);
    for (BluetoothDevice device : pairedDevices) {
      print("Paired devices by name:");
      println(device.getName());
      if (device.getName().equals(device_name)) {
        mmDevice = device;
        println("Bluetooth device name found");
        break;
      }
    }
  }
}

void connect() throws IOException {
  UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
  mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
  mmSocket.connect();
  mmOutputStream = mmSocket.getOutputStream();
  mmInputStream = mmSocket.getInputStream();
  println("Bluetooth connected");
  final byte delimiter = 33; //This is the ASCII code for a ! character
  stop_thread = false;
  buffer_index = 0;
  readBuffer = new byte[1024];
  runThread = new Thread(new Runnable() {
    public void run() {                
      while (!Thread.currentThread().isInterrupted() && !stop_thread) {
        try {
          int bytesAvailable = mmInputStream.available();                        
          if (bytesAvailable > 0) {
            byte[] packetBytes = new byte[bytesAvailable];
            mmInputStream.read(packetBytes);
            for (int i = 0; i < bytesAvailable; i++) {
              byte b = packetBytes[i];
              if (b == delimiter) {
                byte[] encodedBytes = new byte[buffer_index];
                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                final String data = new String(encodedBytes, "US-ASCII");
                plot(data);
                buffer_index = 0;
              } else {
                readBuffer[buffer_index++] = b;
              }
            }
          }
        } 
        catch (IOException ex) 
        {
          stop_thread = true;
        }
      }
    }
  }
  );
  runThread.start();
}

void closeBluetooth() throws IOException {
  stop_thread = true;
  mmOutputStream.close();
  mmInputStream.close();
  mmSocket.close();
  println("Bluetooth stopped");
}

class Permission {
  PApplet parent;
  boolean requestedPortraitImage = false;

  Permission(PApplet pParent, String permissionName) {
    parent = pParent;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
  }

  void onPermissionResult(boolean granted) {
    if (granted)  println("User did grant permission.");
    else println("User did NOT grant permission.");
  }
}

void onPause() {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onPause();
}

void onStop () {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onStop();
}

void onRestart() {
  try {
    findBluetooth();
    connect();
  } 
  catch (IOException ex) {
    println(ex);
  }
}
Sender
  • Arduino code
#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial mySerial(11, 12); // RX, TX

float a = 0;
int y = 0;

void setup() {
  mySerial.begin(115200); // Set the baudrate equal to HC06 setting
}

void loop() {
  y = int(80*sin(a));
  a += 0.08;
  if (a > TWO_PI) a = 0;
  mySerial.print(String(y) + '!');
}
  • Processing code
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 
import processing.core.PConstants;
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Activity activity;
Permission bp, afl;

Thread runThread;
byte[] readBuffer;
int buffer_index;
boolean stop_thread, init = true;
String device_name = "HC-05";
boolean permissions_granted;
String Str = " "; 
String t_str;
float a, increment = 0.04;
int y;

void setup() {
  fullScreen();
  orientation(LANDSCAPE);
  bp = new Permission(this, "BLUETOOTH");
  afl = new Permission(this, "ACCESS_FINE_LOCATION");
  textAlign(CENTER);
  textSize(70);
  t_str = "Click to connect.";
  textSize(12); // To create a "text width factor",
  float twf = width/textWidth(t_str);
  int f = 4; // Empericaly found 
  textSize(f*twf); // Making it  proportional for other screen resolutions
}

void draw() {
  if (init) {
    background(150);
    text(t_str, width/2, height/2);
    strokeWeight(10);
    noFill();
    stroke(50);
    rect(0, 0, width, height);
  } else {
    y = int(80 * sin(a));
    a += increment;
    if (a > TWO_PI)  a = 0;
    try {
      sendData();
    }  
    catch (IOException ex) {
    }
  }
}

void mousePressed () {
  if (init) {
    try {
      init = false;
      findBluetooth();
      connect();
      background(80);
      text("Connecting to send.", width/2, height/2);
    } 
    catch (IOException ex) {
      println(ex);
    }
  }
}

void sendData() throws IOException {
  mmOutputStream.write(y);
}

void findBluetooth() {
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
    println("No bluetooth adapter available");
  }
  if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(enableBluetooth, 0);
  }
  Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
    print("Paired devices MAC Adress:");
    printArray(pairedDevices);
    for (BluetoothDevice device : pairedDevices) {
      print("Paired devices by name:");
      println(device.getName());
      if (device.getName().equals(device_name)) {
        mmDevice = device;
        println("Bluetooth device name found");
        break;
      }
    }
  }
}

void connect() throws IOException {
  UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
  mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
  mmSocket.connect();
  mmOutputStream = mmSocket.getOutputStream();
  mmInputStream = mmSocket.getInputStream();
  println("Bluetooth connected");
  final byte delimiter = 33; //This is the ASCII code for a ! character
  stop_thread = false;
  buffer_index = 0;
  readBuffer = new byte[1024];
  runThread = new Thread(new Runnable() {
    public void run() {                
      while (!Thread.currentThread().isInterrupted() && !stop_thread) {
        try {
          int bytesAvailable = mmInputStream.available();                        
          if (bytesAvailable > 0) {
            byte[] packetBytes = new byte[bytesAvailable];
            mmInputStream.read(packetBytes);
            for (int i = 0; i < bytesAvailable; i++) {
              byte b = packetBytes[i];
              if (b == delimiter) {
                byte[] encodedBytes = new byte[buffer_index];
                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                final String data = new String(encodedBytes, "US-ASCII");
                //plot(data);
                buffer_index = 0;
              } else {
                readBuffer[buffer_index++] = b;
              }
            }
          }
        } 
        catch (IOException ex) 
        {
          stop_thread = true;
        }
      }
    }
  }
  );
  runThread.start();
}

void closeBluetooth() throws IOException {
  stop_thread = true;
  mmOutputStream.close();
  mmInputStream.close();
  mmSocket.close();
  println("Bluetooth stopped");
}

class Permission {
  PApplet parent;
  boolean requestedPortraitImage = false;

  Permission(PApplet pParent, String permissionName) {
    parent = pParent;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
  }

  void onPermissionResult(boolean granted) {
    if (granted)  println("User did grant permission.");
    else println("User did NOT grant permission.");
  }
}

void onPause() {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onPause();
}

void onStop () {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onStop();
}

void onRestart() {
  try {
    findBluetooth();
    connect();
  } 
  catch (IOException ex) {
    println(ex);
  }
}
Combined
  • Arduino code
#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial mySerial(11, 12); // RX, TX

unsigned long previous_millis;
boolean new_data = false;
float a = 0, b = 0;
float i_1 = 0, i_2 = 0;
int udi_1 = 20, udi_2 = 1;
int y_1 = 0, y_2 = 0;
const byte number_of_chars = 32;
char receivedChars[number_of_chars];

void setup() {
  mySerial.begin(115200); // Set the baudrate equal to HC06 setting
  Serial.begin(9600);
}

void loop() {
  receivePacket();
  if (new_data == true) {
    parseData();
    new_data = false;
  }
   while (mySerial.available() <= 0) { 
    y_1 = int(70 * sin(a));
    a += i_1;
    if (a > TWO_PI) a = 0;
    mySerial.print(String(y_1) + '!');

    y_2 = int(70 * sin(b));
    b += i_2;
    if (b > TWO_PI) b = 0;
    mySerial.print(String(y_2) + '#');
  }
}


void receivePacket() {
  static boolean receiving = false;
  static byte index = 0;
  char start_mark = '<';
  char end_mark = '>';
  char rc;
  while (mySerial.available() > 0 && new_data == false) {
    rc = mySerial.read();
    if (receiving == true) {
      if (rc != end_mark) {
        receivedChars[index] = rc;
        index++;
        if (index >= number_of_chars) {
          index = number_of_chars - 1;
        }
      } else {
        receivedChars[index] = '\0';
        receiving = false;
        index = 0;
        new_data = true;
      }
    } else if (rc == start_mark) {
      receiving = true;
    }
  }
}

void parseData() {
  char * split;
  split = strtok(receivedChars, ",");
  udi_1 = atoi(split);
  split = strtok(NULL, ",");
  udi_2 = atoi(split);
  i_1 = udi_1/100.0;
  i_2 = udi_2/100.0;
  Serial.println(i_1);
  Serial.println(i_2);
}
  • Processing code
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 
import processing.core.PConstants;
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Activity activity;
Permission bp, afl;

Thread runThread;
byte[] readBuffer;
int buffer_index;
int counter;
boolean stop_thread, plotting = false, init = true;
boolean drag_just_finished;

String msg = "<0,0>";
String device_name = "HC-05";
String r_str, t_str;
boolean permissions_granted;
float a, b;
float px_1, py_1, x_1, y_1, px_2, py_2, x_2, y_2;
float loc_1, loc_2, num_1 = 0, num_2 = 0;
String[] y_values = {"0#0"};

void setup() {
  fullScreen();
  orientation(LANDSCAPE);
  bp = new Permission(this, "BLUETOOTH");
  afl = new Permission(this, "ACCESS_FINE_LOCATION");
  textAlign(CENTER);
  textSize(70);
  t_str = "Click to connect.";
  textSize(12); // To create a "text width factor",
  float twf = width/textWidth(t_str);
  int f = 4; // Empericaly found 
  textSize(f*twf); // Making it  proportional for other screen resolutions
  loc_1 = width/50;
  loc_2 = width/50;
}

void draw() {
  if (plotting  == false && init) {
    background(150);
    text(t_str, width/2, height/2);
    strokeWeight(10);
    noFill();
    stroke(50);
    rect(0, 0, width, height);
  } else if (plotting  == false) {
    drawSliderOne();
    drawSliderTwo();
  }
}

void mousePressed () {
  if (init) {
    try {
      init = false;
      findBluetooth();
      connect();
      plotting = true;
      fill(0, 0, 90);
      rect(0, 0, width, height); 
      drawSliderOne();
      drawSliderTwo();
    } 
    catch (IOException ex) {
      println(ex);
    }
  }
}

void mouseDragged() {
  plotting = false;
  if (mouseY > height-height/8) {
    loc_1 = mouseX;
    if (loc_1 < width/50) loc_1 = width/50;
    if (loc_1 > width-width/50) loc_1 = width-width/50;
    try {
      sendData();
    }  
    catch (IOException ex) {
    }
  } 
  if (mouseY > height-height/3 && mouseY < height-height/3+height/8) {
    loc_2 = mouseX;
    if (loc_2 < width/50) loc_2 = width/50;
    if (loc_2 > width-width/50) loc_2 = width-width/50;
    try {
      sendData();
    }  
    catch (IOException ex) {
    }
  }
}

void mouseReleased() {
  plotting = true;
}

void drawSliderOne() {
  pushStyle();
  noStroke();
  num_1 = map(loc_1, 0.0, width, 2, 10);
  fill(100, 180, 200);
  rect(0, height-height/8, width, height/8); 
  fill(200, 200, 255);
  rect(width/50, height-height/16, width-width/25, height/100); 
  fill(100, 100, 255);
  ellipse(loc_1, height-height/17, height/20, height/20);
  popStyle();
} 

void drawSliderTwo() {
  pushStyle();
  noStroke();
  num_2 = map(loc_2, 0.0, width, 2, 10);
  fill(100, 180, 200);
  rect(0, height-height/3, width, height/8); 
  fill(200, 200, 255);
  rect(width/50, height-9*height/32, width-width/25, height/100); 
  fill(100, 100, 255);
  ellipse(loc_2, height-9*height/32, height/20, height/20);
  popStyle();
}    

void plot(String r_str) {
  if (r_str.length() < 3 || r_str == null) r_str =  "0#0";
  if (plotting) {
    y_values = split(r_str, "#");
    stroke(0, 200, 255);
    strokeWeight(2);
    y_1 = int(y_values[0])+height/6;
    line(px_1, py_1, x_1, y_1);
    py_1 = y_1;
    px_1 = x_1;
    x_1++;
    if (x_1 > width) {
      x_1 = y_1 = px_1 = py_1 = x_2 = y_2 = px_2 = py_2 = 0;
      fill(0, 0, 90);
      rect(0, 0, width, height-height/3);
    }
    y_2 = int(y_values[1])+height/2;
    line(px_2, py_2, x_2, y_2);
    py_2 = y_2;
    px_2 = x_2;
    x_2++;
  }
}

void sendData() throws IOException {
  msg = "<"+int(num_1)+","+int(num_2)+">";
  mmOutputStream.write(msg.getBytes());
}


void findBluetooth() {
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
    println("No bluetooth adapter available");
  }
  if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(enableBluetooth, 0);
  }
  Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
    print("Paired devices MAC Adress:");
    printArray(pairedDevices);
    for (BluetoothDevice device : pairedDevices) {
      print("Paired devices by name:");
      println(device.getName());
      if (device.getName().equals(device_name)) {
        mmDevice = device;
        println("Bluetooth device name found");
        break;
      }
    }
  }
}

void connect() throws IOException {
  UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
  mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
  mmSocket.connect();
  mmOutputStream = mmSocket.getOutputStream();
  mmInputStream = mmSocket.getInputStream();
  println("Bluetooth connected");
  //final Handler handler = new Handler(); 
  final byte delimiter = 33; //This is the ASCII code for a ! character
  stop_thread = false;
  buffer_index = 0;
  readBuffer = new byte[1024];
  runThread = new Thread(new Runnable() {
    public void run() {                
      while (!Thread.currentThread().isInterrupted() && !stop_thread) {
        try {
          int bytesAvailable = mmInputStream.available();                        
          if (bytesAvailable > 0) {
            byte[] packetBytes = new byte[bytesAvailable];
            mmInputStream.read(packetBytes);
            for (int i = 0; i < bytesAvailable; i++) {
              byte b = packetBytes[i];
              if (b == delimiter) {
                byte[] encodedBytes = new byte[buffer_index];
                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                final String data = new String(encodedBytes, "US-ASCII");
                plot(data);
                buffer_index = 0;
              } else {
                readBuffer[buffer_index++] = b;
              }
            }
          }
        } 
        catch (IOException ex) 
        {
          stop_thread = true;
        }
      }
    }
  }
  );
  runThread.start();
}

void closeBluetooth() throws IOException {
  stop_thread = true;
  mmOutputStream.close();
  mmInputStream.close();
  mmSocket.close();
  println("Bluetooth stopped");
}

class Permission {
  PApplet parent;
  boolean requestedPortraitImage = false;

  Permission(PApplet pParent, String permissionName) {
    parent = pParent;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
  }

  void onPermissionResult(boolean granted) {
    if (granted)  println("User did grant permission.");
    else println("User did NOT grant permission.");
  }
}

void onPause() {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onPause();
}

void onStop () {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onStop();
}

void onRestart() {
  try {
    findBluetooth();
    connect();
  } 
  catch (IOException ex) {
    println(ex);
  }
}

2 Likes

noel

1

1h

Thank you for your interest, it seems to be a special work. I will study the code in detail and then apply it … and I will inform you of what is new

Bless you

On request, another example code, displaying the analog read value of an Arduino equipped with a potentiometer and an HC-05 Bluetooth module.

Analog Read
  • Arduino code
#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial mySerial(11, 12); // RX, TX

int value = 0;
int previous_value = 0;

void setup() {
  mySerial.begin(115200); // Set the baudrate equal to HC06 setting
}

void loop() {
  for (int i = 0; i < 32; i++) value += analogRead(0);
  value /= 32;
  if( value != previous_value) mySerial.print(String(value) + '!');
  previous_value = value;
  delay(100);
}
  • Processing code
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 
import processing.core.PConstants;
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Activity activity;
Permission bt, afl;

Thread runThread;
byte[] readBuffer;
int buffer_index;
int counter;
boolean stop_thread, plotting = false, init = true;

String msg = " ";
String device_name = "HC-05";
String r_str = " ";
String str_1, str_2, str_3;
float px, py, x, y;
int ts_1, ts_2, ts_3;

void setup() {
  fullScreen();
  orientation(LANDSCAPE);
  bt = new Permission(this, "BLUETOOTH");
  afl = new Permission(this, "ACCESS_FINE_LOCATION");
  textAlign(CENTER, CENTER);
  textSize(12);
  str_1 = "Click to connect.";
  str_2 = "8888";
  str_3 = "Analog reading value";
  textSize(12); // Start value to create a "textwidth factor",
  // Making it  proportional for other screen resolutions
  float twf_1 = width/textWidth(str_1);
  float twf_2 = width/textWidth(str_2);
  float twf_3 = width/textWidth(str_3);
  int f_1 = 4; // Empericaly found 
  int f_2 = 11;
  int f_3 = 8;
  ts_1 = int(f_1*twf_1);
  ts_2 = int(f_2*twf_2);
  ts_3 = int(f_3*twf_3);
  fill(255);
  activity = this.getActivity();
}

void draw() {
  if (init) {
    background(150);
    textSize(ts_1); 
    text(str_1, width/2, height/2);
  }
}

void mousePressed () {
  if (init) {
    try {
      init = false;
      findBluetooth();
      connect();
      plotting = true;
      background(0);
      fill(255, 255, 0);
      textSize(ts_3); 
      text(str_3, width/2, height/8);
      textSize(ts_2);
    } 
    catch (IOException ex) {
      println(ex);
    }
  }
}

void plot(String r_str) {
  if (r_str.length() < 1 || r_str == null) r_str =  "0";
  if (plotting) {
    fill(0);
    rect(0, height/3, width, 2*height/3);
    fill(255, 255, 0);
    text(r_str, width/2, 2*height/3);
  }
}

void findBluetooth() {
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
    println("No bluetooth adapter available");
  }
  if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(enableBluetooth, 0);
  }
  Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
    print("Paired devices MAC Adress:");
    printArray(pairedDevices);
    for (BluetoothDevice device : pairedDevices) {
      print("Paired devices by name:");
      println(device.getName());
      if (device.getName().equals(device_name)) {
        mmDevice = device;
        println("Bluetooth device name found");
        break;
      }
    }
  }
}

void connect() throws IOException {
  UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
  mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
  mmSocket.connect();
  mmOutputStream = mmSocket.getOutputStream();
  mmInputStream = mmSocket.getInputStream();
  println("Bluetooth connected");
  final byte delimiter = 33; //This is the ASCII code for a ! character
  stop_thread = false;
  buffer_index = 0;
  readBuffer = new byte[1024];
  runThread = new Thread(new Runnable() {
    public void run() {                
      while (!Thread.currentThread().isInterrupted() && !stop_thread) {
        try {
          int bytesAvailable = mmInputStream.available();                        
          if (bytesAvailable > 0) {
            byte[] packetBytes = new byte[bytesAvailable];
            mmInputStream.read(packetBytes);
            for (int i = 0; i < bytesAvailable; i++) {
              byte b = packetBytes[i];
              if (b == delimiter) {
                byte[] encodedBytes = new byte[buffer_index];
                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                final String data = new String(encodedBytes, "US-ASCII");
                plot(data);
                buffer_index = 0;
              } else {
                readBuffer[buffer_index++] = b;
              }
            }
          }
        } 
        catch (IOException ex) 
        {
          stop_thread = true;
        }
      }
    }
  }
  );
  runThread.start();
}

void closeBluetooth() throws IOException {
  stop_thread = true;
  mmOutputStream.close();
  mmInputStream.close();
  mmSocket.close();
  println("Bluetooth stopped");
}

class Permission {
  PApplet parent;
  boolean requestedPortraitImage = false;

  Permission(PApplet pParent, String permissionName) {
    parent = pParent;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
  }

  void onPermissionResult(boolean granted) {
    if (granted)  println("User did grant permission.");
    else println("User did NOT grant permission.");
  }
}

void onPause() {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onPause();
}

void onStop () {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onStop();
}

void onRestart() {
  try {
    findBluetooth();
    connect();
  } 
  catch (IOException ex) {
    println(ex);
  }
}

1 Like

2 Likes

Thanks noel

Great! I didn’t expect to see my ECG sketch with the AD8232 module working on my phone over Bluetooth. Thanks a ton! :smiley:

1 Like

hi noel

explain this line please

String[] y_values = {"0#0"};///  {"0#0"} what is this ?

It’s just to give an initial value. It could be {99#99} as well, as long it has the ‘#’ delimiter character between two numbers. It will be used in the code thereafter to split the string into two values to be placed in the y_values array. One for each sinewave channel. You can use more delimiters if you want for more channels.

void plot(String r_str) {
  if (r_str.length() < 3 || r_str == null) r_str =  "0#0";
  if (plotting) {
    y_values = split(r_str, "#");

The main delimiter is the ‘!’ character within the connect function in this line:

final byte delimiter = 33; //This is the ASCII code for a ! character

If needed you can change it.

like this ?

void plot(String r_str) {
  if (r_str.length() < 3 || r_str == null) r_str =  "0#0";
  if (plotting) {
    y_values = split(r_str, "#");
    stroke(0, 200, 255);
    strokeWeight(2);
    y_1 = int(y_values[0])
    
    
    }
    y_2 = int(y_values[1])
    
  }
 y_3 = int(y_values[2])

}

Yes, but then you have to send three values like Str = “23#117#50!” or something.

like this

void plot(String r_str) {
  if (r_str.length() < 3 || r_str == null) r_str =  “23#117#50!” 
  if (plotting) {

hi noel
i send 2 values from arduino its working how to increase for 6 values

float  x, y;
String[] y_values = {"0#0"};
 
  void setup() {

 
  }
 
   void plot(String Str) { 
  if (Str.length() < 3 || Str == null) Str =  "0#0";
  if (plotting) {
    stroke(0, 200, 255);
    strokeWeight(2);
   // y = int(Str);
    
   y_values = split ( Str,"#");
   x= int( y_values[0]);
   rect( x,566,45,555);
  }

   y= int( y_values[1]);
   rect( y,566,45,555);
}
what to add to get other rect ?
 
}
what to add to get other rect ?
}
what to add to get other rect ?
}
what to add to get other rect ?
}

and in arduino side what add ?

void loop() {
 
  
  mySerial.print(String(333) + '!');
 mySerial.print(String(555) + '#');

  mySerial.print(String(236) ; adding what ?

 mySerial.print(String(333) ; adding what ?
 mySerial.print(String(555) ; adding what ?

  mySerial.print(String(236) ;// adding what ?

Let’s say your Arduino has 4 sensors.
In the main loop of the arduino sketch, you will add a ‘!’ delimitor only at the first sensor data, because this is the main delimiter. On the subsequent ones you use the ‘#’ delimiter, like:

while (mySerial.available() <= 0) { 
    y_1 = int(data_sensor_1);
    mySerial.print(String(y_1) + '!');

    y_2 = int(data_sensor_2);
    mySerial.print(String(y_2) + '#');

    y_3 = int(data_sensor_3);
    mySerial.print(String(y_3) + '#');

    y_4 = int(data_sensor_4);
    mySerial.print(String(y_4) + '#' );
  }

In the processing sketch, in the plot() function, you will receive a string to be split only on the ‘#’ delimiter, because the main delimiter ‘!’ was already captured, spit and removed in the connect() function.
The channel data can now be split in the plot() function as follows.

void plot(String r_str) {
  if (r_str.length() < 7 || r_str == null) r_str =  "0#0#0#0";
  if (plotting) {
    y_values = split(r_str, "#");
    y_1 = int(y_values[0])
    y_2 = int(y_values[1])
    y_3 = int(y_values[2])
    y_4 = int(y_values[3])
  }
}

Please if you have further questions post them here, to not extend this topic too much.

1 Like

One more request; this time a display of the axis position of a motor. Here the object is drawn in the draw() loop instead of the plot() event, the latest is faster and excellent for wave-line plotting, but not as stable as draw();

Code
  • Arduino code (just used for testing, because I don’t have the hardware.
#include <SoftwareSerial.h>

SoftwareSerial mySerial(11, 12); // RX, TX
int value = 0;

void setup() {
  mySerial.begin(115200); // Set the baudrate equal to HC06 setting
}

void loop() {
  mySerial.println(value);
  value++;
  delay(5);
  if(value > 1023) value = 0;
}
  • Processing code
import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Build.VERSION_CODES; 
import processing.core.PConstants;
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Activity activity;
Permission bt, afl;
Knob knob_1;

Thread runThread;
byte[] readBuffer;
int buffer_index;
int counter;
boolean stop_thread, plotting = false, init = true;
String myString = null;
String msg = " ";
String device_name = "HC-05";
String r_str = " ";
String t_str;
String incoming_position = "";
float px, py, x, y;
float s_angle = 0;
float position_in_degree = 0;

void setup() {
  fullScreen();
  orientation(PORTRAIT);
  bt = new Permission(this, "BLUETOOTH");
  afl = new Permission(this, "ACCESS_FINE_LOCATION");
  knob_1 = new Knob(width/2, height/3, int(width/1.5));
  textAlign(CENTER);
  textSize(70);
  t_str = "Click to connect.";
  textSize(12); // To create a "text width factor",
  float twf = width/textWidth(t_str);
  int f = 6; // Empericaly found 
  textSize(f*twf); // Making it  proportional for other screen resolutions
  activity = this.getActivity();
}

void draw() {
  if (plotting  == false && init) {
    background(150);
    text(t_str, width/2, height/2);
  } else {
  background(100);
  knob_1.render(s_angle);
  fill(255);
  text("Position in Degree: ", width/2, 2*height/3);
  text(int(degrees(s_angle)), width/2, 2*height/3+1.5*textAscent());
  text("RAW Position:", width/2, 3*height/4);
  text(incoming_position, width/2, 3*height/4+1.5*textAscent());
  }
}

void mousePressed () {
  if (init) {
    try {
      init = false;
      findBluetooth();
      connect();
      plotting = true;
      fill(0, 0, 90);
      rect(0, 0, width, height); 
    } 
    catch (IOException ex) {
      println(ex);
    }
  }
}

void plot(String r_str) {
  if(r_str.length() < 1 || r_str == null) r_str = "0";
  incoming_position = r_str;
  s_angle = map(float(r_str), 0, 1024, 0, TWO_PI);
}

class Knob {
  float size, slice, angle;
  PVector center;

  Knob(int x, int y, int diameter) {
    this.center = new PVector(x, y);
    this.size = diameter;
    this.slice = TWO_PI/24; 
  }

  void render(float angle) {
    pushStyle();
    pushMatrix();
    translate(center.x, center.y);
    noFill();
    strokeWeight(size/100);
    stroke(255);
    ellipse(0, 0, size, size);
    float e;
    for (int i = 0; i < 24; i++) {
      if(i % 6 == 0) e = size/18;
      else e = 0;
      line(size*0.41, 0, size*0.47+e, 0);
      rotate(slice);
    }
    rotate(angle);
    line(0, 0, size*0.47, 0);
    popMatrix();
    popStyle();
  }
}

void findBluetooth() {
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
    println("No bluetooth adapter available");
  }
  if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(enableBluetooth, 0);
  }
  Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
    print("Paired devices MAC Adress:");
    printArray(pairedDevices);
    for (BluetoothDevice device : pairedDevices) {
      print("Paired devices by name:");
      println(device.getName());
      if (device.getName().equals(device_name)) {
        mmDevice = device;
        println("Bluetooth device name found");
        break;
      }
    }
  }
}

void connect() throws IOException {
  UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
  mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
  mmSocket.connect();
  mmOutputStream = mmSocket.getOutputStream();
  mmInputStream = mmSocket.getInputStream();
  println("Bluetooth connected");
  final byte delimiter = 10; //This is the ASCII code for a lf
  stop_thread = false;
  buffer_index = 0;
  readBuffer = new byte[1024];
  runThread = new Thread(new Runnable() {
    public void run() {                
      while (!Thread.currentThread().isInterrupted() && !stop_thread) {
        try {
          int bytesAvailable = mmInputStream.available();                        
          if (bytesAvailable > 0) {
            byte[] packetBytes = new byte[bytesAvailable];
            mmInputStream.read(packetBytes);
            for (int i = 0; i < bytesAvailable; i++) {
              byte b = packetBytes[i];
              if (b == delimiter) {
                byte[] encodedBytes = new byte[buffer_index];
                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                final String data = new String(encodedBytes, "US-ASCII");
                plot(data);
                buffer_index = 0;
              } else {
                readBuffer[buffer_index++] = b;
              }
            }
          }
        } 
        catch (IOException ex) 
        {
          stop_thread = true;
        }
      }
    }
  }
  );
  runThread.start();
}

void closeBluetooth() throws IOException {
  stop_thread = true;
  mmOutputStream.close();
  mmInputStream.close();
  mmSocket.close();
  println("Bluetooth stopped");
}

class Permission {
  PApplet parent;
  boolean requestedPortraitImage = false;

  Permission(PApplet pParent, String permissionName) {
    parent = pParent;
    parent.requestPermission("android.permission."+permissionName, "onPermissionResult", this);
  }

  void onPermissionResult(boolean granted) {
    if (granted)  println("User did grant permission.");
    else println("User did NOT grant permission.");
  }
}

void onPause() {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onPause();
}

void onStop () {
  try {
    closeBluetooth();
  } 
  catch (Exception ex) {
  }
  super.onStop();
}

void onRestart() {
  try {
    findBluetooth();
    connect();
  } 
  catch (IOException ex) {
    println(ex);
  }
}

1 Like

@J_Silva

Are you willing to share the ECG sketch for AD8232 module? Recently purchased one but don’t have it working on Android.