Pairing to a CC2540 Bluetooth LE Device - android

I am trying to connect to a BLE devices based on CC2540 from TI (I have the keyfob from TI, and another device from connectblue OLP425) with my Motorola RAZR, the only succes I had so far is an app named Propagation on the market that I don't have access to the sources.
I tried to connect to the device with this code but the biggest thing I don't understand is the UUID,
I downloaded an app on a iPad 3 and I found a device has the following UUID
00000000-0000-0000-ff31-1a064f8c5966
private static final UUID SPP_UUID = UUID.fromString("00000000-0000-0000-ff31-1a064f8c5966");
BluetoothDevice bd =BluetoothAdapter.getDefaultAdapter().getBondedDevices().iterator().next();
//I only have I device paired that is the Bluetooth Low Energy Device so using the first Device returned by the iterator is fine.
try {
BluetoothSocket bs = bd.createRfcommSocketToServiceRecord(UUID);
bs.connect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
All I get is a Service discovery failed in logcat
In almost all the example everyone is using
00000000-0000-1000-8000-00805f9b34fb
If I go further in the app it syas that the battery service is UUID 0x180f
I would just like to create an app the read the value of this service which is a simple decimal value
anyone has any succes pairing with a BLE device in the past?
thank you
Jonathan

I've been able to connect to my CC2540 with the Heart Rate Monitor.
I flashed the firmware using the CCDebugger and using 0000180d-0000-1000-8000-00805f9b34fbas the UUID i've been able to read a value.
Using the Motorola_BLE_profile sample app with some modifications.
primaryServices = mGattService.getGattPrimaryServices(device);
if (primaryServices == null) {
String message = "Connection failed !";
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
return;
}
for (i = 0; i < primaryServices.length; i++) {
Log.v(TAG, "primary service " + primaryServices[i]);
if (primaryServices[i].equalsIgnoreCase(hrmUUID)) {
try {
status = mGattService.connectGatt(device, hrmUUID, callback1);
if (status == true){
mDevice = device;
mLeState = CONNECTING;
BluetoothLeReceiver.isDevicePickerPending = false;
} else {
String message = "Connection failed !";
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG,"Exception while calling gatt Connect");
}
return;
if (i == primaryServices.length) {
Log.v(TAG,"Primary Service not found");
String message = "Connection failed !";
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
}

Related

Android bluetooth connection to ELM327/OBD2 device

I tried to create a simple android application to connect to my ELM327 device to get some car diagnostic data. But I wasn't able to set up the bluetooth connection b/t my android phone and my ELM327 device.
My code is very simple as below:
public class Bluetooth {
protected BluetoothAdapter mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
private ConnectThread mConnectThread = null;
private AcceptThread mAcceptThread = null;
private WorkerThread mWorkerThread = null;
private BluetoothDevice mOBDDevice = null;
private BluetoothSocket mSocket = null;
private String uuid;
Bluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices;
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
return;
pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
//TODO: check whether this is OBD and whether it is connected
//by sending a command and check response
if (deviceName.contains("OBD")) {
mOBDDevice = device;
uuid = device.getUuids()[0].toString();
break;
}
}
}
mBluetoothAdapter.cancelDiscovery();
}
/**
* Start the chat service. Specifically start AcceptThread to begin a session
* in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void connect()
{
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
mSocket = mOBDDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
}
}
In the mainactivity, I will first new a Bluetooth class then call bluetooth.connect():
mBluetooth = new Bluetooth();
mBluetooth.connect();
When I debug the program, I was able to get my ELM327 bluetooth device by querying all the bonded devices with a name of "OBD". I also was able to get the device's uuid and create a socket using createRfcommSocketToServiceRecord. But in the connect function, mSocket.connect() always fail with a return value of -1 and get a IOexception.
My questions are:
When my android application connect to the ELM327 device, my android phone is the bluetooth client and my ELM327 device is the bluetooth server, is this understanding correct?
Is there a server program running on my ELM327 device listening and accept incoming connection? Is this defined behavior of ELM327 protocol?
Any idea why mSocket.connect()has failed? Any idea on how to look into this issue? Or any obvious error in my program? Thanks.
problem solved. see source codes below:
public synchronized void connect() throws IOException {
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
mSocket = mOBDDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mSocket.connect();
} catch (IOException e1) {
Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back..", e1);
Class<?> clazz = mSocket.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE};
try {
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[]{Integer.valueOf(1)};
mFallbackSocket = (BluetoothSocket) m.invoke(mSocket.getRemoteDevice(), params);
mFallbackSocket.connect();
mSocket.close();
mSocket = mFallbackSocket;
} catch (Exception e2) {
Log.e(TAG, "Couldn't fallback while establishing Bluetooth connection.", e2);
mSocket.close();
//throw new IOException();
}
}
inputStream = mSocket.getInputStream();
outputStream = mSocket.getOutputStream();
}
I don't know much about Android, although I know about OBD2 and the lot.
It depends on the type of your adapter. If you have a WiFi adapter, you can consider the adapter being the server and you the client. You connect to a socket and then read from it. In the case of a Bluetooth adapter, it's different. If you connect via rfcomm, it's a serial protocol and neither is the server nor the client. If you connect via BTLE, the OBD2 dongle is the Peripheral and you are the Central.
On WiFi adapters, yes. This behavior is not part of ELM327 though. ELM327 only specifies the serial commands. How you transfer these is not part of the spec, since it happens on the layer above (WiFi, rfcomm, BTLE, USB, etc.).
Are you sure that rfcomm works via the socket interface? It's a serial interface, so I would have expected file-like operations.

Failing bluetooth sequence

I'm trying to make a simple connection sequence to a serial bluetooth device at the beginning of my app. Right now, all of this is inside onCreate ():
BT = BluetoothAdapter.getDefaultAdapter();
BT.enable();
if(!BT.isEnabled()) {
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler, REQUEST_ENABLE);
BT.enable();
Toast.makeText(getApplicationContext(), "Bluetooth On.", Toast.LENGTH_LONG).show();
//finish apk
finish();
}
else {
Toast.makeText(getApplicationContext(), "Bluetooth On.", Toast.LENGTH_LONG).show();
}
pairedDevices = BT.getBondedDevices();
pDevices = new ArrayList<BluetoothDevice>();
if (pairedDevices.size()>0) {
for(BluetoothDevice bt : pairedDevices)
{
pDevices.add(bt); //Get the device's name and the address
}
}
else {
Toast.makeText(getApplicationContext(), "Nothing paired.", Toast.LENGTH_LONG).show();
}
try {
BluetoothDevice dispositivo = BT.getRemoteDevice(pDevices.get(0).getAddress());
btSocket = dispositivo.createInsecureRfcommSocketToServiceRecord(myUUID);
btSocket.connect();
}
catch (IOException e){
Toast.makeText(getApplicationContext(), "Failed.", Toast.LENGTH_LONG).show();
}
The goal is to connect to the first available paired device. So far it always displays "Failed." even when I have an unconnected paired device sitting next to the phone.
Should I be doing this somewhere else in the app? I'm not really concerned with delaying the main activity since this is for a personal project.
Edit: spelling
All BT 2.1 devices and newer ones require the secure connection, so use the createRfcommSocketToServiceRecord instead of the createInsecureRfcommSocketToServiceRecord.
I actually figured it out... It was trying to connect to only the first paired connection. I put the try catch on a for loop, now it connects fine :)

Bluetooth Connection: insecure connections, secure connections, listening securely or insecurely, what to use?

I'm struggling with getting consistent bluetooth connections in a star topology. I have one master phone which is a Samsung Galaxy S4 running API 10. All of the phones that connect to the bluetoothserver socket on the S4 are LG Dynamic Tracfones also running API 10.
Over the past few days, I have seen a LOT of conflicting information on the web about what type of connection to use.
This is my current set up:
MASTER CODE
public void acceptConnection() {
.... (enable bt adapter) ...
// initializes a Bluetooth server socket
bluetoothServerSocket = bc.createBluetoothServerSocket();
//connection made to Master, discovery no longer needed
bluetoothAdapter.cancelDiscovery();
BluetoothSocket bluetoothSocket;
// loops until the thread is interrupted or an exception occurs
while (!isInterrupted()) {
try {
// attempts to accept the slave application's connection
bluetoothSocket = bluetoothServerSocket.accept();
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
Log.v("Default Thread", "Connection to slave failed.");
// breaks out of the while loop
return;
}
try {
... (enumerate all input and output streams, and all bt sockets) ...
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
}
}
This is the method that is called when creating a blueToothServerSocket, and this is where half of my confusion is. How should I listen on the adapter? Currently, I'm doing it insecurely.
public BluetoothServerSocket createBluetoothServerSocket() {
// gets the name of the application
String name = "PVCED";
// gets a common UUID for both the master and slave applications
UUID uuid = UUID.fromString("23ea856c-49da-11e4-9e35-164230d1df67");
// initializes an empty Bluetooth server socket
serverSocket = null;
try {
// creates a Bluetooth socket using a common UUID
serverSocket = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(name, uuid);
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
}
return serverSocket;
}
SLAVE CODE
And this is where the other half of my confusion is, how should I create a socket? Currently I'm doing it insecurely.
private BluetoothSocket createBluetoothSocket(Set<BluetoothDevice> pairedDevices) {
// gets a common UUID for both the master and slave applications
UUID uuid = UUID.fromString("23ea856c-49da-11e4-9e35-164230d1df67");
// initialises an empty Bluetooth socket
BluetoothSocket bluetoothSocket = null;
// checks to see if there are any paired devices
if (pairedDevices.size() > 0) {
// loops through each paired device
for (BluetoothDevice device : pairedDevices) {
// checks to see if the name of the paired device is MASTER
if (device.getName().equals("MASTER")) {
try {
master = device;
// creates a Bluetooth socket using a common UUID
//bluetoothSocket = master.createRfcommSocketToServiceRecord(uuid);
//Method m = master.getClass().getMethod("createRfcommSocketToServiceRecord", new Class[] {int.class});
//bluetoothSocket = (BluetoothSocket) m.invoke(master, 1);
bluetoothSocket = master.createInsecureRfcommSocketToServiceRecord(uuid);
} catch(Exception e){
Log.v("Connect Exception", e.getMessage());
}
}
}
}
//check if we paired succesfully to a master, if not, prompt user to do so.
if (master == null){
... (tell user to pair with master via toast) ...
}
return bluetoothSocket;
}
My logcat is often filled with errors such as "Bad File Descriptor", "Unable to start Service Discovery", or "Service Discovery has failed."
What is the best connection scheme to use for my scenario? If you guys need more details on how I'm enabling/disabling bt adapters, or closing bt connections, I can supply more code.

Android Bluetooth pairing Security

Since I upgraded to android 4.2 I'm having trouble when I try to pair a device
The device should be paired but now it says that across_user_permission is required.
Here is the error log :
error:code 3:
java.lang.SecurityException::
Permission Denial: broadcast from android asks to run as user -1 but is
calling from user0; this requires
android.permission.INTERACT_ACROSS_USERS_FULL or
android.permission.INTERACT_ACROSS_USERS.
and here my method :
public boolean ensurePaired(BluetoothDevice bd) {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(bd.getAddress());
boolean paired = false;
Log.d(TAG,"Pairing with Bluetooth device with name " + device.getName()+" and address "+device.getAddress());
try {
Method m = device.getClass().getMethod("createBond");
paired = (Boolean) m.invoke(device);
} catch (Exception e)
{
return paired;
}
Log.d("BluetoothPlugin -", "Returning "+ "Result: "+paired);
return paired;
}
I would change the code to:
public boolean ensurePaired(BluetoothDevice bd) {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(bd.getAddress());
Log.d(TAG,"Pairing with Bluetooth device with name " + device.getName()+" and address "+device.getAddress());
if(device.getBondState() != BluetoothDevice.BOND_BONDED){
device.createBond();
}
}
createBond is an asynchronous call, it will return immediately. Register for ACTION_BOND_STATE_CHANGED intents to be notified when the bonding process completes, and its result.

How to send AT commands based on BT Hands-Free profile in android?

I am trying to establish Bluetooth connection between an Android device with other mobile phone over Handsfree profile. I am using following code -
private static final UUID MY_UUID = UUID.fromString("0000111F-0000-1000-8000-00805F9B34FB"); // UUID for Hands free profile
// Some code...
// Get Bluetooth Adapter.
m_oBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Some code...
// For paired BT device, getting a connection established.
if(null != m_oBluetoothDevice)
{
if(BluetoothDevice.BOND_BONDED == m_oBluetoothDevice.getBondState())
{
try
{
m_oBluetoothSocket = m_oBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
m_oBluetoothSocket.connect();
Log.i(TAG, "Socket Connected");
}
catch(Exception e)
{
if(null != m_oBluetoothSocket)
{
Log.i(TAG, "Closing socket");
try
{
m_oBluetoothSocket.close();
}
catch (Exception e1)
{
Log.i(TAG, "Error while closing socket : " + e1.getMessage());
}
}
}
}
}
I can create RFCOMMSocket using this code.
Now I want to send AT commands based on Bluetooth Hands-Free profile. e.g. If other mobile phone receives a phone call, my Android device can reject this call by sending AT command- "+CHUP". I am not sure whether this is possible or not.
At this point, I am stuck. I have read Bluetooth APIs where I found -
BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT
Can we use this Intent for sending AT commands? Is this a proper way to send AT command based on Bluetooth Hands-Free profile? Please someone help me out and give me proper direction.
Any input from you all will be great help for me.
Thanks in advance.
You need to create InputStream and OutputStream so you can talk to the phone:
mmInStream = m_oBluetoothSocket.getInputStream();
mmOutStream = m_oBluetoothSocket.getOutputStream();
To setup the HFP connection you start to send:
mmOutStream.write("AT+BRSF=20\r".getBytes());
Where 20 is code for what you support of HFP.
And to read from the phone:
buffer = new byte[200];
mmInStream.read(buffer);
command = new String(buffer).trim();
So now you can talk beetwen the devices and you can read more about the Handsfree profile on https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=238193
Adding reference to AT commnads
http://forum.xda-developers.com/showthread.php?t=1471241
http://www.zeeman.de/wp-content/uploads/2007/09/ubinetics-at-command-set.pdf

Categories

Resources