I have written an Android app that's supposed to send data to Arduino Due via Bluetooth Module (ZS-040). Bluetooth connection is fine. However, Arduino doesn't seem to receive any data from Android. When I send data to Arduino through the Serial Monitor though, it works. I've looked into many stackoverflow questions and other guides online but can't seem to figure out what's wrong.
Here's some code:
Thread for connecting the two devices:
private class ConnectThread extends Thread {
private BluetoothDevice mmDevice;
private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//uuid for Arduino bluetooth module
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { };
socket = tmp;
}
public void run() {
mBluetoothAdapter.cancelDiscovery();
runOnUiThread(new Runnable() {
#Override
public void run() {
findBtn.setText("Search for devices");
}
});
try {
socket.connect();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
}
});
} catch (IOException connectionException) {
try {
socket.close();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "An error has occured. Please try again.",
Toast.LENGTH_SHORT).show();
}
});
} catch (IOException closeException) { }
return;
}
}
}
Code for sending data to Arduino; function is called when a button is pressed.
public void sendData(View view) {
// write to OutputStream
OutputStream mmOutputStream = null;
try {
mmOutputStream = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
e.printStackTrace();
}
// String message = "0";
// byte[] msgBuffer = message.getBytes();
try {
mmOutputStream.write('0');
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
e.printStackTrace();
}
}
Arduino code (directly copied from here):
char incomingByte; // incoming data
int LED = 12; // LED pin
void setup() {
Serial.begin(9600); // initialization
pinMode(LED, OUTPUT);
Serial.println("Press 1 to LED ON or 0 to LED OFF...");
}
void loop() {
if (Serial.available() > 0) { // if the data came
incomingByte = Serial.read(); // read byte
if(incomingByte == '0') {
digitalWrite(LED, LOW); // if 1, switch LED Off
Serial.println("LED OFF. Press 1 to LED ON!"); // print message
}
if(incomingByte == '1') {
digitalWrite(LED, HIGH); // if 0, switch LED on
Serial.println("LED ON. Press 0 to LED OFF!");
}
}
}
EDIT: Because it's a DUE with which I'm working, I can't use SoftwareSerial library. :(
I've figured it out after much debugging with both hardware and software. Serial refers to rx0 and tx0 on the Due board. However, when the board is powered by the computer via usb cable (usb-to-serial to be exact), rx0 receives data from the computer instead of the bluetooth even when it's connected. Changing it to other serial such as Serial1 (rx1 and tx1), Serial2 (rx2, tx2) and Serial3 (rx3, tx3) in the Arduino code prevents that from happening.
Related
I have two devices connected through Bluetooth now. After that, I disconnected the Bluetooth connection on the Client device, and the broadcast receiver in this Client device can detect the disconnection, and then switch it back to previous activity. Something like this:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Message msg = Message.obtain();
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
try {
Log.i("Disconnecting3", "Disconectinggg....");
Intent intent1 = new Intent(Main3Activity.this, MainActivity.class);
startActivity(intent1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
Anyhow, on my other device which is the Server device, this device CAN NOT detect the disconnection despite the Bluetooth socket is closed! The broadcast receiver in the Server device cannot detect the disconnection. FYI, below code will show how I close the Bluetooth socket on the Server device when the Client device is disconnected.
private boolean CONTINUE_READ_WRITE;
CONTINUE_READ_WRITE = true;
public void run() {
try {
while (CONTINUE_READ_WRITE) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = handleSeacrh.obtainMessage(MessageConstants.MESSAGE_READ, numBytes, -1, mmBuffer);
readMsg.sendToTarget();
} catch (IOException e) {
//nothing();
CloseConnection closeConnection = new CloseConnection();
closeConnection.start();
break;
}
}
} catch (Exception e) {
// Log.d(TAG, "Input stream was disconnected", e);
}
}
public void cancel() {
try {
Log.i("TAG", "Trying to close the socket");
CONTINUE_READ_WRITE = false;
mBluetoothSocket.close();
mmBluetoothSocket.close();
Log.i("TAG", "I thinked its still closing");
} catch (IOException e) {
Log.e("TAG", "Could not close the connect socket", e);
}
}
So when there is a disconnection happened on the Client device, the while(CONTINUE_READ_WRITE)..loop will break the loop and start a new Thread. Something like this :
private class CloseConnection extends Thread {
public void run(){
Log.i("Running","Runinnggggg");
try {
mmInStream.close();
mmOutStream.close();
bluetoothDataTransmission.cancel();
Log.i("Interrupted","InteruppteDDDD");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Alright, I found a solution , just need to add this line of code
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
I want to listen for incoming messages through bluetooth when pairing totally completed. I can't call listen(can I?) before the pairing is completed and I can't know when it is completed.
I tried a lot of methods to pair between two devices like this one:
private void pairDevice() {
try {
BluetoothDevice device = bluetooth.getRemoteDevice(address);
Log.d("pairDevice()", "Start Pairing...");
Method m = device.getClass().getMethod("createBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Log.d("pairDevice()", "Pairing finished.");
} catch (Exception e) {
Log.e("pairDevice()", e.getMessage());
}
}
this one works nice but it opens a popup to accept the pairing and theLog.d("pairDevice()", "Pairing finished."); is called before the popup dialog is being accepted and I need to do things only when the pairing is totally completed and the devices are now paired. here is my code for listening for messages:
public void run() {
final int BUFFER_SIZE = 1024;
byte[] buffer = new byte[BUFFER_SIZE];
int bytes = 0;
int b = BUFFER_SIZE;
while (true) {
try {
bytes = inStream.read(buffer, bytes, BUFFER_SIZE - bytes);
textview.setText(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
here is my code for sending the message(score):
private void init() throws IOException {
if (bluetooth != null) {
if (bluetooth.isEnabled()) {
Set<BluetoothDevice> bondedDevices = bluetooth.getBondedDevices();
if (bondedDevices.size() > 0) {
ParcelUuid[] uuids = device.getUuids();
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuids[0].getUuid());
socket.connect();
outputStream = socket.getOutputStream();
inStream = socket.getInputStream();
write(score);
}
Log.e("error", "No appropriate paired devices.");
} else {
Log.e("error", "Bluetooth is disabled.");
}
}
}
public void write(String s) throws IOException {
outputStream.write(s.getBytes());
}
I tried to pair two devices without user permission like in this answer -here- but it also asked for permissions i don't know why .. So actually I don't think I need pairing without permission I just need doing something when popup accepted. is it possible? thanks.
I'm making an app that needs to connect with a bluetooth device and get data from it... that device is set as master, so I needed to implement a Thread, where I listenUsingRfcommWithServiceRecord and wait for a connection from it:
public AcceptThread(Context context, String serverName, UUID myUUID) {
this.context = context;
BluetoothServerSocket tmp = null;
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(serverName, myUUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
Then on run I run the code socket = mmServerSocket.accept(5000) to wait until it starts pairing with the device:
public void run() {
BluetoothSocket socket = null;
while (true) {
try {
socket = mmServerSocket.accept(5000);
} catch (IOException e) {
Log.e(TAG,"IOException: " + e);
}
// If a connection was accepted
if (socket != null) {
// Manage the connection
ManageConnectedSocket manageConnectedSocket = new ManageConnectedSocket(socket);
manageConnectedSocket.run();
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "IOException: " + e);
}
break;
}
}
}
The Device asks for an authentication PIN, and I need to have an automatic procedure... for that I though of implementing a broadcast receiver to know when the device is asked to par with another device:
IntentFilter filter = new IntentFilter(ACTION_PAIRING_REQUEST);
context.registerReceiver(mPairReceiver, filter);
and receive it:
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_PAIRING_REQUEST.equals(action)) {
Log.e(TAG,"ACTION_PAIRING_REQUEST");
setBluetoothPairingPin(device);
}
}
};
In my setBluetoothPairingPin method I receive a BluetoothDevice object :
public void setBluetoothPairingPin(BluetoothDevice device) {
byte[] pinBytes = convertPinToBytes("0000");
try {
Log.e(TAG, "Try to set the PIN");
Method m = device.getClass().getMethod("setPin", byte[].class);
m.invoke(device, pinBytes);
Log.e(TAG, "Success to add the PIN.");
try {
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, false);
Log.e(TAG, "Success to setPairingConfirmation.");
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
}
The problem is that I can't know when my socket receives information, and consecutively, can't know what is my BluetoothDevice to set Pairing Pin before it's connected...
Can someone help me on how to surpass this? Or is there other way to put the pin authentication when I'm listenning from BluetoothServerSocket?
If I'm not explaining correctly, please let me know...
Thanks in advance
With the help from this and this, I was able to make work for me...
My confusion was with the method setBluetoothPairingPin that I couldn't understand that the ACTION_PAIRING_REQUEST is actually called when the device is being starting to pairing, and that is when the PIN is asked from the user... so invoking BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);, and changing a bit of the set pairing method I manage to make it work...
Here's my final code:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_PAIRING_REQUEST.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String PIN = "0000";
byte[] pin = new byte[0];
try {
pin = (byte[]) BluetoothDevice.class.getMethod("convertPinToBytes", String.class).invoke(BluetoothDevice.class, PIN);
BluetoothDevice.class.getMethod("setPin", byte[].class).invoke(device, pin);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
I am writing an app on Android Studio.
I communicate from an Android device to an arduino board via Bluetooth.
For now everything works but i am starting a new Activity and i need to stop the actual BT connection. so i want to call a stop method.
The problem is that it crash when i call it.
here is the code
public class BtInterface {
private BluetoothDevice device = null;
private BluetoothSocket socket = null;
private InputStream receiveStream = null;
private OutputStream sendStream = null;
String GlobalBuff="";
String Right_Buff="";
private ReceiverThread receiverThread;
Handler handler;
public BtInterface(Handler hstatus, Handler h,String Device_Name) {
Set<BluetoothDevice> setpairedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
BluetoothDevice[] pairedDevices = (BluetoothDevice[]) setpairedDevices.toArray(new BluetoothDevice[setpairedDevices.size()]);
for(int i=0;i<pairedDevices.length;i++) {
if(pairedDevices[i].getName().contains(Device_Name)) {
device = pairedDevices[i];
try {
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
receiveStream = socket.getInputStream();
sendStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
handler = hstatus;
receiverThread = new ReceiverThread(h);
}
public void sendData(String data) {
sendData(data, false);
}
public void sendData(String data, boolean deleteScheduledData) {
try {
sendStream.write(data.getBytes());
sendStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void connect() {
new Thread() {
#Override public void run() {
try {
socket.connect();
Message msg = handler.obtainMessage();
msg.arg1 = 1;
handler.sendMessage(msg);
receiverThread.start();
} catch (IOException e) {
Log.v("N", "Connection Failed : " + e.getMessage());
e.printStackTrace();
}
}
}.start();
}
public void close() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket=null; //???
}
public BluetoothDevice getDevice() {
return device;
}
private class ReceiverThread extends Thread {
Handler handler;
ReceiverThread(Handler h) {
handler = h;
}
#Override public void run() {
while(true) {
try {
if(receiveStream.available() > 0) {
byte buffer[] = new byte[1000];
int k = receiveStream.read(buffer, 0, 1000);
if(k > 0) {
byte rawdata[] = new byte[k];
for(int i=0;i<k;i++)
rawdata[i] = buffer[i];
String data = new String(rawdata);
GlobalBuff= GlobalBuff+data;
Right_Buff= GlobalBuff.substring(GlobalBuff.length()-1,GlobalBuff.length());
if(Right_Buff.equals("\n")){
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("receivedData", GlobalBuff);
msg.setData(b);
handler.sendMessage(msg);
GlobalBuff="";
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
i try some extra code :
receiverThread.interrupt();
receiverThread=null;
if (receiveStream != null) {
try {receiveStream.close();} catch (Exception e) {}
receiveStream = null;
}
if (sendStream != null) {
try {sendStream.close();} catch (Exception e) {}
sendStream = null;
}
before closing but the result is the same , it crash.
The strange behavior is that it didn't crash immediately as it could happen with a type error or else ( i am talking of the behavior in debug mode...)
If anybody got an idea.
Googling this bring me to people with this issue but no solution that works for my case.
Thanks
UPDATE
what i found as a trace when it crash is that :
06-02 07:45:27.369 9025-9133/fr.icservice.sechage A/libc? Fatal signal 11 (SIGSEGV) at 0x00000008 (code=1), thread 9133 (Thread-1436)
I also made a test on a sony Z3 phone under 5.0.2 (compare to my T210 samsung galaxy tab3 under 4.4.2)and it not crash..!
maybe it's a ROM bug?! or a android version problem...
This is a known problem (or bug?) on Android. If you close the Bluetooth socket and then access it later on, some devices will crash with a segmentation fault (like yours). A common workaround is to check socket.isConnected() before or to synchronize the access to close(), write(), read(), ... by setting a flag like closeWasCalled = true and prevent any further calls to methods of this socket in your code after a close() call.
The problem comes with Socket Input/Output. I faced this problem when disconnecting with peer bluetooth device.
Reason :
From code, we are trying to read() , write() from socket object/connection which is closed.
Solution :
Add checking socket.isConnected() before above operations
You can read more about this problem on Stack Overflow question : Here
I'm having issues with connecting. At first it works, than it does not, unless I unpair the devices.
I've gotten every possible exception that could happen, socket closed, pipe closed, connection refused, port already in use, etc.
I'm aware that there are issues with bluetooth on android pre 4.2 (https://code.google.com/p/android/issues/detail?id=37725).
Devices that I'm having problems with connecting these devices:
Htc one(android 4.2)
samsung galaxy s2(android 4.1.2)
nexus 4 (4.3)
samsung galaxy s4 (4.2)
Another minor issue is, that the paired devices are not stored (mostly on the nexus 4, and the sgs2).
Here is my code:
private static final UUID MY_UUID_SECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //this is the other one that I've tried: fa87c0d0-afac-11de-8a39-0800200c9a66");
private static final String NAME = "BluetoothConnector";
public void listenForConnection() throws IOException, BluetoothException {
//first close the socket if it is open
closeSocket();
BluetoothServerSocket mServerSocket = null;
try {
mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID_SECURE); //ioexception here!
} catch (IOException e) {
if (Build.VERSION.SDK_INT >= 9) {
try { //this is a stupid hack, http://stackoverflow.com/questions/6480480/rfcomm-connection-between-two-android-devices
Method m = mBluetoothAdapter.getClass().getMethod("listenUsingRfcommOn", new Class[] { int.class });
mServerSocket = (BluetoothServerSocket) m.invoke(mBluetoothAdapter, PORT);
} catch (Exception ex) {
Log.e(ex);
throw e;
}
} else {
throw e;
}
}
while (!isCancelled) {
try {
socket = mServerSocket.accept();
} catch (IOException e) {
if (socket != null) {
try {
socket.close();
} finally {
socket = null;
}
}
throw e;
}
if (socket == null) {
throw new BluetoothException("Socket connection connected, but null");
} else {
isConnected = true;
break; // everything is ok
}
}
}
public void connect(String address) throws IOException, BluetoothException {
mBluetoothAdapter.cancelDiscovery();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
try {
socket = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
} catch (IOException e1) {
Log.e(e1);
if (Build.VERSION.SDK_INT >= 9) {
try {
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
socket = (BluetoothSocket) m.invoke(device, PORT);
} catch (Exception e) {
Log.e(e);
throw e1;
}
} else {
throw e1;
}
}
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket.connect();
} catch (IOException e) {
Log.e(e);
// Close the socket
try {
socket.close();
} catch (IOException e2) {
Log.e(e2);
Log.wtf("unable to close() socket during connection failure");
}
throw e;
}
}
private void closeSocket() {
try {
if (socket != null) {
socket.close();
socket = null;
Log.d("Socket closed");
}
} catch (IOException e) {
Log.e(e);
Log.wtf("close() of connect socket failed");
}
}
I tried changing the uuid(random one also), tried looking at older sdk samples.
So what could be wrong here?
edit: trying to clarify: the problem usually comes up, when 2 devices that have been paired, connected, did some successful communication, get disconnected (by the user). After that, they can not be reconnected, unless they get rebooted, or unpaired manually.
You are trying to paired this manner:
private void TwitPairedDevice() {
buttonTwitPairDevice.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Set<BluetoothDevice> fetchPairedDevices=bluetooth.getBondedDevices();
Iterator<BluetoothDevice> iterator=fetchPairedDevices.iterator();
while(iterator.hasNext())
{
final BluetoothDevice pairBthDevice=iterator.next();
final String addressPairedDevice=pairBthDevice.getAddress();
AsyncTask<Integer, Void, Void> asynchPairDevice=new AsyncTask<Integer, Void, Void>() {
#Override
protected Void doInBackground(Integer... params) {
try {
socket=pairBthDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
};asynchPairDevice.execute();
}
}
});
}
Connect Pired Device:
private void FetchPairedDevices() {
Set<BluetoothDevice> pairedDevices=bluetooth.getBondedDevices();
for(BluetoothDevice pairedBthDevice:pairedDevices)
{
listPairedDevice.add(pairedBthDevice.getName());
}
listviewPairedDevice.setAdapter(adapterPairedDevice);
listviewPairedDevice.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Object listPairedName=arg0.getItemAtPosition(arg2);
String selectedPairedName=listPairedName.toString();
Set<BluetoothDevice> bthDeviceChecking=bluetooth.getBondedDevices();
for(final BluetoothDevice bthDevice:bthDeviceChecking)
{
if(bthDevice.getName().contains(selectedPairedName))
{
listPairDevice.clear();
listPairDevice.add(bthDevice);
final String addressPairedDevice=bthDevice.getAddress();
AsyncTask<Integer, Void, Void> asynTask=new AsyncTask<Integer,Void,Void>() {
#Override
protected Void doInBackground(Integer... params) {
try {
socket=bthDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
asynTask.execute(arg2);
}
}
}
});
}
It seems that at this point Bluetooth is broken on android.
There is no sure way of connecting 2 devices, that works all the time.
Some people are using an unofficial way to do it, but that does not work on all devices.
I did some in house testing, with the top 10 devices, that are on the market currently, so after around around 90 test runs, the hacked method worked 75% of the time, which is not good enough.
For example, the htc oneX will just handle incoming Bluetooth request, as a Bluetooth hands free device(it is connecting succesfully!), but makes messaging impossible.
After implementing full Bluetooth functionality, we decided to remove it from our app, and release it without it. We'll switch to wifi in some later release.