Bluetooth communication b/w Android and IOT device - android

I am trying to establish Bluetooth communication between Android and IOT (intel galileo) device.
The code at IOT side (i am keeping it as a client), it will send data to android, but here one port number is hard coded. This is in python.
def record_transmit_to_subscriber(self, subscriber, message):
server_addr = subscriber
port = 6
client_socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
try:
client_socket.connect((server_addr, port))
client_socket.send(message)
client_socket.close()
return True
except Exception as e:
print "Unable to make connection with subscriber", subscriber
return False
Now at android (server) side:
private static UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
try {
BluetoothServerSocket tmp = null;
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
try {
// MY_UUID is the applications UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
GlobalUtils.writeLogFile("Error in BLE Listening " + e.getMessage());
}
mmServerSocket = tmp;
} catch (Exception e){
GlobalUtils.writeLogFile("Exception in Accept Thread " + e.getMessage());
}
I do believe there in some problem in this code, at client side it is using port number while at server side it is using uuid. can someone please rectify how to modify this code to make connection work.

Seems You forgot to create socket and streams:
try {
BluetoothDevice bluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("<MAC_address_of_your_device>");
mSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
mSocket.connect();
} catch (IOException e) {
Log.e(TAG, "Fail connect");
}
// Get the input and output streams for BT socket
try {
inStream = mSocket.getInputStream();
outStream = mSocket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Fail to open socket streams");
}
Than You can create Thread for read data from inStream (for example inStream.read(<data_buffer>); and Thread for write data to outStream (for example outStream.write(<data_buffer>); outStream.flush();).

Related

Bluetooth connection problems

I have a client on a PC and a server on a tablet. I know the MAC addresses for both which means I do not do discoveries.
1. On the client if I use
connectString = "btspp://" + MACaddress + ":4;authenticate=false;encrypt=false;master=false";
It connects fine.
If I change the CN number (4) to anything else, it does not work. How is this number determined?
2. Everything works fine if the tablet is a Samsung with Android 5.0.2 When I use a Qunyico tablet with Android 10, it does not work. I get an error: Failed to connect; [10051] A socket operation was attempted to an unreachable network. What is the problem?
Client on PC – code taken from “Bluetooth-java-client-master”
public class IrcBluetoothClient {
private static void openConnection(String MACaddress) throws IOException {
// Tries to open the connection.
String connectString = "btspp://" + MACaddress + ":4;authenticate=false;encrypt=false;master=false";
StreamConnection connection = (StreamConnection) Connector.open(connectString);
if (connection == null) {
System.err.println("Could not open connection to address: " + MACaddress);
System.exit(1);
}
// Initializes the streams.
OutputStream output = connection.openOutputStream();
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(isr);
// Starts the listening service for incoming messages.
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(new IncomingMessagesLoggingRunnable(connection));
// Main loop of the program which is not complete yet
LocalDevice localDevice = LocalDevice.getLocalDevice();
while (true) {
String toSend = reader.readLine();
byte[] toSendBytes = toSend.getBytes(StandardCharsets.US_ASCII);
output.write(toSendBytes);
System.out.println("[" + localDevice.getFriendlyName() + " - " +
localDevice.getBluetoothAddress() + "]: " + toSend);
System.exit(1);
}
Server on tablet – code taken from https://developer.android.com/guide/topics/connectivity/bluetooth
private static final UUID A_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public BTacceptConnections( BluetoothAdapter mBluetoothAdapter) {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
BluetoothServerSocket tmp = null;
try {
// A_UUID is the app's UUID string, also used by the client code.
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, A_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
// Closes the connect socket and causes the thread to finish.
public void cancel(){
try {
mmServerSocket.close();
}catch (IOException e){
}
runFlag = 1;
}
//***********************************************************************************************
//
// This thread runs all the time listening for incoming connections.
//
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (runFlag == 0) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) { // If a connection was accepted
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
// manageMyConnectedSocket(socket);
}else{
try {
mmServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
I know the MAC addresses for both which means I do not do discoveries.
Official Linux Bluetooth protocol stack BlueZ uses D-BUS API to establish bluetooth communication. If you check adapter-api, scanning will create device objects that you need to establish a communication which means discovering is not only done to retrieve MAC addresses only.
Your case might be the same, I would suggest doing discovery first.

Android sending info via Bluetooth, fast logging

I am trying to write an app that passes the coordinates of a ball to Arduino via BT. The coordinates are being sent every 4 ms. For this test I send "123" instead of full coordinates. What am I getting now (on Arduino serial monitor) is "123123123123123..." and it refreshes only after I close the application.
What I want to achieve is "123" in every line, that shows immediately after the message is sent.
Android code BT:
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private OutputStream outStream ;
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
mBluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
Log.i(TAG, "run: CONNECTED");
} catch (IOException connectException) {
Log.i(TAG, "run: NOT CONNECTED");
}
}
// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
if(outStream != null)
outStream.close();
finish();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
//Sending Message
public void writeData(String data){
String info = data;
try {
outStream = mmSocket.getOutputStream();
outStream.write(info.getBytes());
Log.i(TAG, "writeData: MSG SENT");
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "run: CANT SEND MSG");
}
}
public boolean isConnected(){
return mmSocket.isConnected();
}
}
In my main function I call:
if(connectThread.isConnected())
connectThread.writeData("123");
Arduino code:
String incomingByte;
void setup() {
//pinMode(53, OUTPUT);
Serial.begin(9600);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
incomingByte = Serial.readString();
Serial.println(incomingByte);
delay(10);
}
}
There is no concept of messages in serial communication, unless you make it yourself.
Serial.readString() delimits your "messages" with time (1 second by default) and you are sending "messages" 4 ms apart. This obviously concatenates your "messages".
To actually send messages you need to delimit them. You can do that by sending lines.
On Android, you need to end the message with a new line character:
outStream.write(info.getBytes());
outStream.write(10); // send a new line character (ASCII code 10)
And on Arduino, you need to read, until you find a new line character:
incomingByte = Serial.readStringUntil('\n');
Serial.read(); // remove the leftover new line character from the buffer
You need to put at least \n (or maybe \r\n) after the coordinates, or the Bluetooth module just keeps buffering.

Android code to receive data from non-android bluetooth device

I am going through a scenario in which I need to receive data from a NON-Android device (say, a PC with Bluetooth Dongle). I need to display my own UI and want to handle the incoming data by my application itself. So is there any good way to achieve this goal.
--Edit
As #Trevor mentioned in his answer, the following para have no meaning, I only understood the fact after a little long study about the topic. Anyway, Thanks for all for there suggestions.
So far I tried with listenUsingRfcommWithServiceRecord(...) and createRfcommSocketToServiceRecord(...) but in this way, we need to run our application in both the devices. Currently its not my case.
--Edit
So, is there any good way to receive data from a NON-Android device?
Thanks in advance...
Your question is a little vague because you haven't explained exactly what problems have occurred when you've tried to connect to whatever Bluetooth device it is you're trying to use. Your second paragraph ("So far I tried with listenUsingRfcommWithServiceRecord(...) and createRfcommSocketToServiceRecord(...) but in this way, we need to run our application in both the devices. Currently its not my case.") doesn't make sense to me.
However, I'm assuming it's a SPP device you're trying to connect to (that is, a Bluetooth to Serial interface, or a USB PC Bluetooth dongle set up with a virual COM port). In this case, you can use the Bluetooth Chat example code pretty much as it is, except for one important change which is to use the SPP UUID:
/** UUID for Serial Port Profile */
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
By the way, if you use the Bluetooth Chat example as the basis of your project, beware of a bug I found in the Bluetooth Chat code which causes received characters to be lost if they're received at anything faster that typing speed. For information on this, refer to my answer given here: Android InputStream dropping first two bytes (modified BluetoothChat)
in android sdk sample take a Look at the BluetoothChat,
you need two thread to communicate the data
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
this.mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));
} catch (IOException e) {
e.printStackTrace();
}
mmSocket = tmp;
}
#Override
public void run() {
setName("ConnectThread");
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
connectionFailed();
return;
}
synchronized (PrinterService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e("PrinterService", "close() of connect socket failed", e);
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Printer Service", "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
#Override
public void run() {
while (true) {
try {
if (!encodeData(mmInStream)) {
mState = STATE_NONE;
connectionLost();
break;
} else {
}
// mHandler.obtainMessage(AbstractActivity.MESSAGE_READ,
// bytes, -1, buffer).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
connectionLost();
PrinterService.this.stop();
break;
}
}
}

Android (2.2.1) Bluetooth: HTC Wildfire: Connecting to PC from Android: Have to change UUID every time?

I have a Bluetooth server listening for incoming connection, on the Laptop.
Android is a client and wants to connect to PC.
What's wrong?
I can connect first time and send data to PC. When I turn off the Android Activity and start it again, connect function passes, but PC does not register new connection. When I try sending the data, android system logs following:
05-16 13:11:17.091: ERROR/BluetoothEventLoop.cpp(102): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/30064/hci0/dev_50_63_13_CB_52_96
What works?
If I change server's UUID, on the server and on the client, it will work again first time I try connection. Consequent tries do not work.
Server code:
/** Waiting for connection from devices */
private void waitForConnection() {
// retrieve the local Bluetooth device object
LocalDevice local = null;
StreamConnectionNotifier notifier;
StreamConnection connection = null;
// setup the server to listen for connection
try {
local = LocalDevice.getLocalDevice();
local.setDiscoverable(DiscoveryAgent.GIAC);
UUID uuid = new UUID("af29e59088cc11e1b0c40800200c9a56", false);
System.out.println(uuid.toString());
String url = "btspp://localhost:" + uuid.toString() + ";name=ThinBTClient";
notifier = (StreamConnectionNotifier)Connector.open(url);
} catch (Exception e) {
e.printStackTrace();
return;
}
// waiting for connection
while(true) {
try {
System.out.println("Wait Thread: Waiting for connection...");
connection = notifier.acceptAndOpen();
System.out.println("Got connection");
Thread processThread = new Thread(new ProcessConnectionThread(connection));
processThread.start();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
Client code:
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
UUID SPP_UUID = UUID.fromString("af29e590-88cc-11e1-b0c4-0800200c9a56");
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
mBluetoothAdapter.cancelDiscovery();
btSocket.connect();
outStream = btSocket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Any ideas?
Update:
I tested the same code on another laptop, Toshiba/Win7 and code works without a problem. So I suspect this is something with drivers. I will try updating.

Connecting Android device to multiple Bluetooth serial embedded peers

I'm trying to find a solution for this setup:
I have a single Android device, which I would like to connect to multiple serial embedded devices...
And here is the thing, using the "Normal" way to retrieve the Bluetooth socket, doesn't work on all devices, and while it does, I can connect to multiple devices, and send and receive data to and from multiple devices.
public final synchronized void connect()
throws ConnectionException {
if (socket != null)
throw new IllegalStateException("Error socket is not null!!");
connecting = true;
lastException = null;
lastPacket = null;
lastHeartBeatReceivedAt = 0;
log.setLength(0);
try {
socket = fetchBT_Socket_Normal();
connectToSocket(socket);
listenForIncomingSPP_Packets();
connecting = false;
return;
} catch (Exception e) {
socket = null;
logError(e);
}
try {
socket = fetchBT_Socket_Workaround();
connectToSocket(socket);
listenForIncomingSPP_Packets();
connecting = false;
return;
} catch (Exception e) {
socket = null;
logError(e);
}
connecting = false;
if (socket == null)
throw new ConnectionException("Error creating RFcomm socket for" + this);
}
private BluetoothSocket fetchBT_Socket_Normal()
throws Exception {
/* The getType() is a hex 0xXXXX value agreed between peers --- this is the key (in my case) to multiple connections in the "Normal" way */
String uuid = getType() + "1101-0000-1000-8000-00805F9B34FB";
try {
logDebug("Fetching BT RFcomm Socket standard for UUID: " + uuid + "...");
socket = btDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
return socket;
} catch (Exception e) {
logError(e);
throw e;
}
}
private BluetoothSocket fetchBT_Socket_Workaround()
throws Exception {
Method m;
int connectionIndex = 1;
try {
logDebug("Fetching BT RFcomm Socket workaround index " + connectionIndex + "...");
m = btDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
socket = (BluetoothSocket) m.invoke(btDevice, connectionIndex);
return socket;
} catch (Exception e1) {
logError(e1);
throw e1;
}
}
private void connectToSocket(BluetoothSocket socket)
throws ConnectionException {
try {
socket.connect();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e1) {
logError("Error while closing socket", e1);
} finally {
socket = null;
}
throw new ConnectionException("Error connecting to socket with" + this, e);
}
}
And here is the thing, while on phones which the "Normal" way doesn't work, the "Workaround" way provides a solution for a single connection. I've searched far and wide, but came up with zip.
The problem with the workaround is mentioned in the last link, both connection uses the same port, which in my case, causes a block, where both of the embedded devices can actually send data, that is not been processed on the Android, while both embedded devices can receive data sent from the Android.
Did anyone handle this before?
There is a bit more reference here,
UPDATE:
Following this (that I posted earlier) I wanted to give the mPort a chance, and perhaps to see other port indices, and how other devices manage them, and I found out the the fields in the BluetoothSocket object are different while it is the same class FQN in both cases:
Detils from an HTC Vivid 2.3.4, uses the "workaround" Technic:
The Socket class type is: [android.bluetooth.BluetoothSocket]
mSocket BluetoothSocket (id=830008629928)
EADDRINUSE 98
EBADFD 77
MAX_RFCOMM_CHANNEL 30
TAG "BluetoothSocket" (id=830002722432)
TYPE_L2CAP 3
TYPE_RFCOMM 1
TYPE_SCO 2
mAddress "64:9C:8E:DC:56:9A" (id=830008516328)
mAuth true
mClosed false
mClosing AtomicBoolean (id=830007851600)
mDevice BluetoothDevice (id=830007854256)
mEncrypt true
mInputStream BluetoothInputStream (id=830008688856)
mLock ReentrantReadWriteLock (id=830008629992)
mOutputStream BluetoothOutputStream (id=830008430536)
**mPort 1**
mSdp null
mSocketData 3923880
mType 1
Detils from an LG-P925 2.2.2, uses the "normal" Technic:
The Socket class type is: [android.bluetooth.BluetoothSocket]
mSocket BluetoothSocket (id=830105532880)
EADDRINUSE 98
EBADFD 77
MAX_RFCOMM_CHANNEL 30
TAG "BluetoothSocket" (id=830002668088)
TYPE_L2CAP 3
TYPE_RFCOMM 1
TYPE_SCO 2
mAccepted false
mAddress "64:9C:8E:B9:3F:77" (id=830105544600)
mAuth true
mClosed false
mConnected ConditionVariable (id=830105533144)
mDevice BluetoothDevice (id=830105349488)
mEncrypt true
mInputStream BluetoothInputStream (id=830105532952)
mLock ReentrantReadWriteLock (id=830105532984)
mOutputStream BluetoothOutputStream (id=830105532968)
mPortName "" (id=830002606256)
mSocketData 0
mSppPort BluetoothSppPort (id=830105533160)
mType 1
mUuid ParcelUuid (id=830105714176)
Anyone have some insight...
WOW, every time this strike me down with one big WTF?
This was a race condition issue, which clearly works on one version of android, and not on another. On Android peer I was parsing the packets received from the socket:
public class SocketListener
implements Runnable {
private boolean stop;
private OnIncomingPacketListener packetListener;
#Override
public void run() {
InputStream inputStream;
try {
stop = false;
inputStream = socket.getInputStream();
while (!stop) {
Packet packet = Packet.getPacket(inputStream);
lastPacket = packet;
if (packet.getDescriptor() == Packet.HeartBeat)
lastHeartBeatReceivedAt = System.currentTimeMillis();
else if (packet.getDescriptor() == Packet.LogEntry)
log.append(((LogEntryPacket) packet).getLogEntry());
synchronized (this) {
if (packetListener != null)
packetListener.onIncomingData(EmbeddedDevice.this, packet);
}
}
} catch (IOException e) {
logError("----- BLUETOOTH IO ERROR -----\n #: " + EmbeddedDevice.this, e);
return;
} catch (RuntimeException e) {
logError("----- BLUETOOTH LISTENER ERROR -----\n #: " + EmbeddedDevice.this, e);
throw e;
} finally {
socketListeningThread = null;
}
}
}
Where the Packet.getPacket(inputStream) is:
public static synchronized Packet getPacketInstance(InputStream inputStream)
throws IOException {
int data = inputStream.read();
Packet type = null;
for (Packet packetType : values())
if (packetType.packetType == data) {
type = packetType;
break;
} // race condition here...
if (type == null)
throw new IllegalArgumentException("Unknown packet type: " + data);
try {
Packet packet = type.incomingPacketType.newInstance();
packet.setDescriptor(type);
packet.readPacketData(inputStream);
return packet;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Error instantiating type: " + type.incomingPacketType.getName(), e);
}
}
And every time a packet is completed, the next thread should have gone in to perform it parsing.
My guess is that there is some sort of lock on the port, that together with my implementation caused the second thread to block indefinitely, once I've removed the parsing to different instances per thread, the issue dissolved.
This insight was inspired by Daniel Knoppel, the guy from the mPort link.
Thanks Daniel!

Categories

Resources