I have followed this example: http://english.cxem.net/arduino/arduino5.php
I have a arduino uno board set up with a sparkfun bluetooth device. I can connect and send data from android to arduino and I see this data pop up in the serial monitor, but I can not send data from the arduino(serial monitor) and back to Android.
I am using a ConnectThread that is started in the onResume method in the activity. This is the code for my thread:
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d("THREAD", "constructor");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.d("THREAD", "inside run" );
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
Log.d("in loop", "waiting for data");
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
Log.d("recieve", "b " + bytes);
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
Log.d("TAG", "...Data to send: " + message + "...");
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
Log.d("TAG", "...Error data send: " + e.getMessage() + "...");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
Do I need to use a service that always waits for data since the serial monitor is only sending data when I press send?
EDIT: Arduino code:
#include <SoftwareSerial.h>
int bluetoothTx = 2; // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3; // RX-I pin of bluetooth mate, Arduino D3
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
void setup()
{
Serial.begin(9600); // Begin the serial monitor at 9600bps
bluetooth.begin(115200); // The Bluetooth Mate defaults to 115200bps
bluetooth.print("$$$"); // Enter command mode
delay(100); // Short delay, wait for the Mate to send back CMD
bluetooth.println("U,9600,N"); // Temporarily Change the baudrate to 9600, no parity
// 115200 can be too fast at times for NewSoftSerial to relay the data reliably
bluetooth.begin(9600); // Start bluetooth serial at 9600
}
void loop()
{
if(bluetooth.available()) // If the bluetooth sent any characters
{
// Send any characters the bluetooth prints to the serial monitor
Serial.print((char)bluetooth.read());
}
if(Serial.available()) // If stuff was typed in the serial monitor
{
char c = (char) Serial.read();
// Send any characters the Serial monitor prints to the bluetooth
bluetooth.print(c);
}
// and loop forever and ever!
}
No you don't need a service, a thread should work fine. This code is practically identical to the code provided in the BluetoothChat sample provide through the Android SDK so it should work.
By using the serial monitor, you are sending data to the Arduino, so I assume you are echoing that data back using Serial.println("data string") or something similar. However, since you followed the article you cited, you have the Bluetooth chip hooked up to the RX/TX pins (0 and 1) on the Arduino, which is the same pins used by the Serial Monitor. I've found that when the Bluetooth chip is hooked up to these, the serial monitor still receives data but can no longer send it. So your problem is on the Arduino side.
Also, this StackOverflow answer mentions that you can't use both the Serial Monitor and Bluetooth on pins 0 and 1 at the same time.
If you still want to use the Serial Monitor, hook up the Bluetooth chip to different digital pins and use the SoftwareSerial Arduino library as described here.
I've made a simple modification to the Bluetooth Chat sample as described in this post and my Android has no problem receiving from the Arduino.
Related
What I have :
HC-05 Bluetooth module
Arduino promini
BPM sensors
Android studio 3.0
What I have done :
Connect the Arduino, sensors, and HC-05 bluetooth using Serial
Send the data from Arduino script
Recieve and get the data using 3rd party apps from playstore
What I wanted to do :
Get the data from arduino's to be showed in the android text view, using native coded apps (not the one from the store) using android studio.
My current code :
Arduino script :
loop(){
Serial.println("*"+String(BPM)+"#"); //BPM from sensor
delay(200)
}
And some code for connecting and pairing using Android Bluetooth Adapter, which I can't showed here full because still hard coded, but the point is :
I made a handler, which recieves incoming inputs from the serial, and at least showing them on Toast component, but still haven't managed to make it work.
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
Toast.makeText(getApplicationContext(),"Data in",Toast.LENGTH_SHORT
).show();// if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
sensorView0.setText("Data from Arduino: " + sbprint); // update TextView
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
I also have a class :
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
Toast.makeText(getApplicationContext(),"Masuk ke handler private class",Toast.LENGTH_SHORT
).show();
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
}
Which I think calls for the handler to read the message, but haven't managed to make it work.
I wanted to at least show the message to the Toast, or TextView, but haven't got a clear answer this last 3 weeks.
So anyone who can help will be appreciated.
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.
I have created an application to Android and Microsoft Hololens, where it is possible to send some GPS-data with bluetooth from an Android-phone to a Hololens (with Bluetooth LE Advertiser) and that works allright. But when I am trying to send other data from Hololens to Android, I have a problem that Android-phone can't discover Hololens, although these devices are paired. Is it even possible to send data from Hololens with bluetooth, or is there only something wrong in my code? Does Bluetooth LE Advertising support two-way data transfering?
I am guessing you have a BluetoothConnected thread in your android app with an InputStream (mine is mmInStream). Try using this as your 'run' function in the thread:
public void run() {
System.out.println("BT THREAD RUNNING");
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
InputStreamReader mmInStreamReader = new InputStreamReader(mmInStream);
BufferedReader mmReader = new BufferedReader(mmInStreamReader);
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
Thread.sleep(100);
String s = mmReader.readLine();
Thread.sleep(100);
//Static class that handles the response
BluetoothCommunications.responseHandler(s);
} catch (IOException e) {
System.out.println("Input stream was disconnected" + e);
main.disconnected();
break;
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
I'm working on an application which should be quite the same as Bluehood, an application which is on the google market .
So now I'm working on Bluetooth . The fact is, I want to transfer strings (JSON) between two devices . I've seen lots of posts on stackoverflow and some examples on the internet but it's not so clear for me .
I know that I've to use createInsecureRfcommSocketToServiceRecord for sending informations and listenUsingInsecureRfcommWithServiceRecord for receiving them , but I'm searching some simple tutorial to explain how it works and how to transfer data between two devices .
Thank in advance for your explanations...
It's hard to know if I am answering this effectively, as you say you have searched the web and I find one of the most useful tutorials at android com on Bluetooth. I have supplied parts of the code, not the full thread classes, but the bones to give you an idea of how temp sockets are used until sockets are found and made final, for the duration of the connection, and how threads manage each stage of the connection process.
listenUsingRfcommWithServiceRecord(NAME, MY_UUID); is used to create a server socket. It listens for a connection. It acts like a server. This is on the device that is acting as a server or listening for incoming connections.
This is done is a separate thread.
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothConnection.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
socket.close();
} catch (IOException e) {
}
break;
}
}
}
}
}
There is a separate thread to act as a client, seeking a connection. It goes looking for a connection. This is on the device that seeks the connection with the server device. (These can be interchangeable).
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run() {
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
You then need a thread to manage the actual connection. When the client meets the server. Also in a separate thread.
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
BluetoothConnection.this.start();
break;
}
}
}
Within this thread you also have your code to manage writing data through this connection.
There are samples supplied through android.com.
I also found this tutorial good, as a simple background into bluetooth discovery and connection, although it doesn't give you all you need to read and write data.
In terms of reading and writing the data, the following snippet is an example of a way to handle reading data and parsing it to something usable. Calling the handler from within the connection thread. In this case I am appending the data to a textView, but you can do whatever you want with it, it shows how to put it into a String. (which is what you are looking for).
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
textView1.append("\nMessage " + messageCount + ": " + readMessage);
....
Likewise there is some code to write messages - this is in the connected thread class. However, I grab this information using an OnClick event with the button to send. Grab the text from the EditText and send it to a function to parse the String to bytes.
where message is a String and mChatService is calling the write method from the Connected thread.
Converting the string to a byte array, so it can be sent.
// Get the message bytes and tell the BTManager to write
byte[] send = message.getBytes();
mChatService.write(send);
Write method from connected thread:
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
}
}
It is worth noting that the states of the devices must be monitored (you can have a look a the tutorial for that).
It is also important to keep the background threads away from the UI. So that is where the skill comes in (and a handler) to transfer data to and from the UI to the socket connection.
I'm facing the following problem:
I am connecting two devices via Bluetooth socket, one tablet android and a bluetooth device like reader barcode, up to now it's ok, the problem is, when a read the barcode by the bluetooth device and I send it to tablet, the bar code sometimes it's sent in two parts, for example, if I read a barcode with content "212154521212", the tablet receive "2121" and after "54521212", Anyone know tell me what should I do to avoid this?
Thanks in advanced.
My code that read the data from bluetooth device:
[code]
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private BluetoothSocket socket;
public ConnectedThread(BluetoothSocket socket) {
this.socket = socket;
InputStream tmpIn = null;
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
new LogDeErrosRodesTablet(e);
Log.e(TAG, e.getMessage());
Log.e(TAG, "Erro no construtor da classe ConnectedThread.");
}
mmInStream = tmpIn;
}
public void run() {
// continua lendo o inputstream até ocorrer um erro
while (true) {
int read = 0;
byte[] buffer = new byte[128];
do {
try {
read = mmInStream.read(buffer);
Log.e(TAG, "read: " + read);
final String data = new String(buffer, 0, read);
Log.e(TAG, "data: " + data);
//TODO
//send data only (bar code) only after read all
Bundle bundle = new Bundle();
bundle.putString(TelaInserirPedido.CODIGO_BARRAS, data);
Message message = new Message();
message.what = TelaInserirPedido.MSG_COD_BARRAS;
message.setData(bundle);
//Send a message with data
handler.sendMessage(message);
} catch(Exception ex) {
read = -1;
return;
}
Log.e(TAG, "inside while.");
} while (read > 0);
Log.e(TAG, "outside of while.");
}
}
public void cancel () {
try {
socket.close ();
} catch ( IOException e) { }
}
}
[/code]
This isn't a Bluetooth error. The Bluetooth device is sending all of the data to your application, but you are reading the stream before all of the data have been received. You could check for the amount of bytes available() on the stream before reading, if you know the exact length of the data; you could concatenate the results of all of the reads until you reach a known end point. Or you could put in an arbitrary time delay and hope the transmission completed in that time.
You would create the Bundle and Message after the while loop that collects the input string, because you don't know the entire string until that loop finishes. (Unless you are expecting multiple strings in one connection, in which case you need more complex code to handle partial numbers).
Use OutputStream.flush() to force send the all data.