So I'm making an app that has to send an Arraylist<String> over a Bluetooth connection. The ArrayList<String> could be hundreds of lines long. I'm just testing it right now with several lines of data. When I transfer data to the other phone, it immediately prints it out to the logcat. It transfers a portion of the start of the line, but then sends a whole bunch of these question marks. When I play around with the byte[] buffer size, lowering it seems to get rid of a lot of question marks but the lines aren't preserved, raising it seems to send more question marks. Anyways - Take a look at the console output:
Console output
Sending code:
public void run() {
btAdapter.cancelDiscovery(); // discovery is heavy on the Bluetooth bandwith
try {
socket.connect();
// Decompile the enter file system of this event into one giant arraylist<string>
EventDecompiler decompiler = new EventDecompiler(getApplicationContext());
ArrayList<String> lines = decompiler.decompile(eventName, false);
ConnectedThread thread = new ConnectedThread(socket);
thread.start();
// First, let the other device know how much information we're sending
thread.write(String.valueOf(lines.size()).getBytes());
for(int i = 0; i < lines.size(); i++) {
thread.write(lines.get(i).getBytes());
}
} catch(IOException e) {
cancel();
return;
}
}
public void write(byte[] bytes) {
try {
outStream.write(bytes);
} catch(IOException e) {}
}
Here's the receiving code:
public void run() {
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
buffer = new byte[1024];
// Read from the InputStream
bytes = inStream.read(buffer);
status.post(new Runnable() {
public void run() {
status.setText("Receiving "+progress+ " / "+total);
}
});
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
private static Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case Constants.MESSAGE_READ:
byte[] readBuf = (byte[])msg.obj;
String string = new String(readBuf);
received.add(string);
if(progress < 1) {
total = 100;
}
progress++;
if(progress == 15) {
for(int i = 0; i < received.size(); i++) {
System.out.println(received.get(i));
}
}
break;
}
}
};
Any ideas of how to dynamically scale the buffer size or something else that's going wrong?
Related
I'm working on a project which receives information from an arduino module and shows it as a chart.
The problem is I have 5 elements ( temperature,humidity, etc... ) and the code I have can only receive one number at a time ( for example : 2838752458 ), as you see in the example the number has 10 digits which comes from Arduino and I want to separate them two by two so each two of them goes for one element.
you might ask why I don't set a handler so I can receive each two number at a separated time but I've tried that and it gives me closed application error because the code I have only can receive one number at a time.
public class Analysies extends AppCompatActivity {
Handler h;
String tekrar = "";
String dama = "";
String qaza = "";
String faaliat = "";
String rotobat = "";
private OutputStream outStream = null;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static String address = "00:21:13:00:02:5B";
final int RECIEVE_MESSAGE = 1; // Status for Handler
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder sb = new StringBuilder();
private Analysies.ConnectedThread mConnectedThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_analysies);
gifImageView = (GifImageView) findViewById(R.id.gifBro);
txt1 = (GifImageView) findViewById(R.id.afterAutotxt);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
txt1.animate().alpha(1f).setDuration(2000);
}
}, 1000);
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
// 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());
sbprint.getBytes().toString();
////////////////////////////// HERE IS WHERE I CAN RECEIVE INFORMATION FROM ARDUINO ///////////////////////////////
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
// Toast.makeText(CommunicationAuto.this, "String:" + sb.toString() , Toast.LENGTH_LONG).show();
break;
}
}
;
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
if(Build.VERSION.SDK_INT >= 10){
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
return (BluetoothSocket) m.invoke(device, MY_UUID);
} catch (Exception e) {
// Toast.makeText(getApplicationContext(), "Could not Insecure", Toast.LENGTH_SHORT).show();
}
}
return device.createRfcommSocketToServiceRecord(MY_UUID);
}
#Override
public void onResume() {
super.onResume();
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
// Toast.makeText(getApplicationContext(), "Socket failed", Toast.LENGTH_SHORT).show();
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
btAdapter.cancelDiscovery();
// Establish the connection. This will block until it connects.
// Toast.makeText(getApplicationContext(), "Connecting", Toast.LENGTH_SHORT).show();
try {
btSocket.connect();
// Toast.makeText(getApplicationContext(), "Connecting ok!", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
// errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
mConnectedThread = new Analysies.ConnectedThread(btSocket);
mConnectedThread.start();
}
#Override
public void onPause() {
super.onPause();
try {
btSocket.close();
} catch (IOException e2) {
// errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
}
}
private void checkBTState() {
// Check for Bluetooth support and then check to make sure it is turned on
// Emulator doesn't support Bluetooth and will return null
if(btAdapter==null) {
Toast.makeText(getApplicationContext(), " Bluetooth is not supported. ", Toast.LENGTH_SHORT).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
private void errorExit(String title, String message){
Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
finish();
}
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 {
// 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;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}
}
}
The question : How can i separate the 10 digit number two by two and add them to separated integers so i can pass them to the chart activity? Please give me an example for "1234567890" this number.
here is the output of the chart I created so far.
This seems to do what you want:
import java.util.regex.*;
public class HelloWorld{
public static void main(String []args){
String s = "1234567890";
String pattern = "(\\d\\d)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(s);
while (m.find()) {
System.out.println(m.group(0));
}
}
}
And output:
12
34
56
78
90
At first make sure the number of your digits (e.g: 1234567890) always divisible by 2. Well, then I have a little hack for you.
First, convert the digits to String and run a for-loop with step 2, then just append the characters at i-th and (i+1)th position into each string producing using the loop into an array. And finally, you can just read item from the array list and send value to your chart just parsing the String into int value to your chart. Here is a sample code I did with Kotlin (but I can convert it into Java code if you need). If you face any issues, feel free to comment.
fun main() {
val digits = 1234567890
val arr = arrayListOf<String>()
for (i in 0 until digits.toString().length step 2) {
val sub = "${digits.toString()[i]}${digits.toString()[i+1]}"
arr.add(sub)
}
println(arr)
}
I want to use data sent from my Arduino to my android. I'm able to connect both together and display the incoming data on my screen. However, when I want to use the incoming data to set comments this doesn't seem to be working. So how can I get the values out of the incoming data?
String address1 = ("98:D3:81:FD:4B:87");
String name1 = ("Sensor_Shoe");
#SuppressLint("HandlerLeak")
protected void bluetoothconnect() {
btEnablingIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
requestCodeForEnable=1;
if (myBluetoothAdapter==null){
Toast.makeText(getApplicationContext(),"Bluetooth not supported", Toast.LENGTH_LONG).show();
} else {
if (!myBluetoothAdapter.isEnabled()) {
startActivityForResult(btEnablingIntent, requestCodeForEnable);
}
if (myBluetoothAdapter.isEnabled()) {
myBluetoothAdapter.disable();
Toast.makeText(getApplicationContext(),"Bluetooth disabled",Toast.LENGTH_SHORT).show();
TextView input1 = findViewById(R.id.input1); input1.setVisibility(View.INVISIBLE);
ImageButton btn_bluetooth = findViewById(R.id.btn_bluetooth); btn_bluetooth.setBackgroundColor(getResources().getColor(R.color.transparent));
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if(requestCode==requestCodeForEnable){
ImageButton btn_bluetooth = findViewById(R.id.btn_bluetooth);
if(resultCode==RESULT_OK){
Toast.makeText(getApplicationContext(),"Bluetooth enabled",Toast.LENGTH_SHORT).show();
TextView input1 = findViewById(R.id.input1); input1.setVisibility(View.VISIBLE);
btn_bluetooth.setBackgroundColor(getResources().getColor(R.color.colorAccent));
createsocket();
}
else if(resultCode==RESULT_CANCELED){
Toast.makeText(getApplicationContext(),"Bluetooth enabling cancelled",Toast.LENGTH_SHORT).show();
TextView input1 = findViewById(R.id.input1); input1.setVisibility(View.INVISIBLE);
btn_bluetooth.setBackgroundColor(getResources().getColor(R.color.transparent));
}
}
}
protected void createsocket() {
new Thread() {
public void run() {
boolean fail = false;
BluetoothDevice device = myBluetoothAdapter.getRemoteDevice(address1);
try {
BTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
BTSocket.connect();
} catch (IOException e) {
try {
fail = true;
BTSocket.close();
BTHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if (!fail) {
mConnectedThread = new ConnectedThread(BTSocket);
mConnectedThread.start();
BTHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name1)
.sendToTarget();
}
}
}.start();
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", UUID.class);
return (BluetoothSocket) m.invoke(device, PORT_UUID);
} catch (Exception e) {
Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
return device.createRfcommSocketToServiceRecord(PORT_UUID);
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.available();
if(bytes != 0) {
buffer = new byte[1024];
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
BTHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
}
This is how I make the connection, this seems to work properly. Than I use the code underneith to read out the incomming data.
BTHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == MESSAGE_READ) {
String readMessage = " ";
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
inputdata1 = readMessage;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
TextView input1 = findViewById(R.id.input1);
input1.setText(readMessage);
if (readMessage.equals("X")){
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(100);
}
}
}
};
Showing the incomming data in the textview works. But it doesn't recognize the X in the incomming data. I can however see that this data is incomming in the textView and i do send this in de arduino code.
if (fsrReadingHeel >= (fsrReadingHeelOld + 800)){
Serial.println("X");
}
I do know the code is processed because when I say if (!(readMessage.equals("X"))){ than it does vibrate.
Arduinos Serial.print sends in ASCII. When you build a String, you can use ASCII like this: Charset.setName("ASCII") instead of just "UTF-8". This works fine for me (with a Arduino Uno and HC-06 Bluetooth module):
readMessage = new String((byte[]) msg.obj, Charset.setName("ASCII"));
The String you created from the byteBuffer should be limited to the size of the actual data - you could use substring(0, sizeOfData) for that.
When I made my App to connect with my Arduino Uno, I had the problem, that depending on the configuration it ignored the first sent Byte in Android, so try to send a longer string and see if you get something, and that you can actually read it correctly.
I am suggesting that you use Serial.print instead of println, because you don't need the line break in sending. It might also change the message you receive on Android.
if (fsrReadingHeel >= (fsrReadingHeelOld + 800)){
Serial.print("X");
}
You could also use Serial.write instead, but you don't need to - have a look at the differences here: https://arduino.stackexchange.com/questions/10088/what-is-the-difference-between-serial-write-and-serial-print-and-when-are-they
I already got displayed data received from microprocesor via bluetooth. It sends me an 8-bit frame with actual Voltage and Temperature state every second.
The issue is the TextView doesn't displaying actual data. When app loads, the data is displayed and stays like that. One method to refresh data is to load app again.
I got handler and ConnectedThread which code I attach.
All the best from Poland.
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
sb.append(readMessage);
int endOfLineIndex = sb.indexOf(";\r\n");
if (endOfLineIndex > 0) {
String dataInPrint = sb.substring(0, endOfLineIndex);
strDlugosc.setText(dataInPrint);
int dataLenght = dataInPrint.length();
strLenght.setText("ilość otrzymanych znakow =" + String.valueOf(dataLenght));
if (sb.charAt(0) == '9') {
String statusb = sb.substring(8,9);
String temperatura = sb.substring(21, 27);
String napiecie = sb.substring(12, 18);
status.setText("Status :" + statusb);
temp_1.setText("TEMPERATURA = " + temperatura + " *C");
nap_1.setText("NAPIECIE = " + napiecie + " V");
}
}
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
//creation of the connect thread
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
try {
//Create I/O streams for connection
tmpIn = socket.getInputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep looping to listen for received messages
while (!ConnectedThread.interrupted()) {
try {
bytes = mmInStream.read(buffer); //read bytes from input buffer
String readMessage = new String(buffer, 0, bytes);
// Send the obtained bytes to the UI Activity via handler
bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
} catch (IOException e) {
break;
}
}
}
I did it before. I used a timer to get data from BlueTooth socket every 1 second
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// get data from socket and set to text view here
}
}, 0, 10000 /** milliseconds **/);
I have created an android app that (theoretically) sends data to the arduino via bluetooth.
I know that I have managed to get connectivity(the led on the bluetooth module stopped blinking) but the Serial.available() isn't changing when I write some values.
I have tried using different apps (from the play store) - no luck.
The arduino code which suppose to read the data:
void setup() {
Serial.begin(9600);
Serial.println("Simple Motor Shield sketch");
}
void loop() {
if(Serial.available()>0){
Serial.println("in");
for(int i=0;i<=2;i++){
joystick[i] = Serial.read();
}
for(int i=0;i<=2;i++){
Serial.println(joystick[i]);
}
delay(1);
}
}
joystick[] is an int array
android code:
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) { //if message is what we want
String readMessage = (String) msg.obj; // msg.arg1 = bytes from connect thread
recDataString.append(readMessage); //keep appending to string until ~
int endOfLineIndex = recDataString.indexOf("~"); // determine the end-of-line
if (endOfLineIndex > 0) { // make sure there data before ~
String dataInPrint = recDataString.substring(0, endOfLineIndex); // extract string
int dataLength = dataInPrint.length(); //get length of data received
recDataString.delete(0, recDataString.length()); //clear all string data
}
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
// Set up onClick listeners for buttons to send 1 or 0 to turn on/off LED
btnLeft.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mConnectedThread.write("0"); // Send "0" via Bluetooth
Toast.makeText(getBaseContext(), "Turn off LED", Toast.LENGTH_SHORT).show();
}
});
btnRight.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mConnectedThread.write("1"); // Send "1" via Bluetooth
Toast.makeText(getBaseContext(), "Turn on LED", Toast.LENGTH_SHORT).show();
}
});
layout_joystick.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
js.drawStick(arg1);
if (arg1.getAction() == MotionEvent.ACTION_DOWN
|| arg1.getAction() == MotionEvent.ACTION_MOVE) {
//int x = js.getX();
//int y = js.getY();
int angle = (int)js.getAngle();
int distance = (int)js.getDistance();
int maxDist = js.getOffset()+js.getLayoutHeight();
distance =(int)(distance/(maxDist/9));
angle=(int)(angle/40);
distance=Math.max(distance,-9);
distance=Math.min(distance,9);
angle=Math.max(angle,-9);
angle=Math.min(angle,9);
//mConnectedThread.write(String.valueOf(x));
//mConnectedThread.write(String.valueOf(y));
mConnectedThread.write(String.valueOf(angle));
mConnectedThread.write(String.valueOf(distance));
Log.i("Bluetooth","Distance: " + distance);
Log.i("Bluetooth","Angle: " + angle);
}
return true;
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
return device.createRfcommSocketToServiceRecord(BTMODULEUUID);
//creates secure outgoing connecetion with BT device using UUID
}
#Override
public void onResume() {
super.onResume();
//Get MAC address from DeviceListActivity via intent
Intent intent = getIntent();
//Get the MAC address from the DeviceListActivty via EXTRA
address = intent.getStringExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
//create device and set the MAC address
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_LONG).show();
}
// Establish the Bluetooth socket connection.
try
{
btSocket.connect();
} catch (IOException e) {
try
{
btSocket.close();
} catch (IOException e2)
{
//insert code to deal with this
}
}
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
//I send a character when resuming.beginning transmission to check device is connected
//If it is not an exception will be thrown in the write method and finish() will be called
mConnectedThread.write("0");
}
#Override
public void onPause()
{
super.onPause();
try
{
//Don't leave Bluetooth sockets open when leaving activity
btSocket.close();
} catch (IOException e2) {
//insert code to deal with this
}
}
//Checks that the Android device Bluetooth is available and prompts to be turned on if off
private void checkBTState() {
if(btAdapter==null) {
Toast.makeText(getBaseContext(), "Device does not support bluetooth", Toast.LENGTH_LONG).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
//create new class for connect thread
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//creation of the connect thread
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
//Create I/O streams for connection
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = mmInStream.read(buffer); //read bytes from input buffer
String readMessage = new String(buffer, 0, bytes);
// Send the obtained bytes to the UI Activity via handler
bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
} catch (IOException e) {
break;
}
}
}
//write method
public void write(String input) {
byte[] msgBuffer = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(msgBuffer); //write bytes over BT connection via outstream
} catch (IOException e) {
//if you cannot write, close the application
Toast.makeText(getBaseContext(), "Connection Failure", Toast.LENGTH_LONG).show();
finish();
}
}
}
I think you have connected Bluetooth module on serial RX,TX pins of arduino board. this is not the case. You need to use separate serial for communication with Bluetooth. You can use software serial for this purpose otherwise Bluetooth module won't work.
The reason behind this is that the arduino uses same serial pins to communicate with PC (Serial terminal and program load) so it cannot simultaneously send data to Bluetooth.
Have a look at here: https://bellcode.wordpress.com/2012/01/02/android-and-arduino-bluetooth-communication/
Sorry for the unclarity, basically what I wanted to do is to check if I had any data available on the bluetooth serial connection.
So I hoped that Serial.available() would be more than 0 when I sent data.Yet, the Serial.available() and Serial.Read() didn't seemed to work when I sent data.
* I have managed to solve the problem using the program from: http://www.circuitmagic.com/arduino/arduino-and-bluetooth-hc-06-to-control-the-led-with-android-device/ *
I am building an android app that will be able to read values from a load sensor. The load sensor is connected to a LCD to display the values of weight applied to the sensor and an Arduino board. I am simply building this app to get the weight values from the LCD/load sensor. I am using HC-06 Bluetooth module, and I am able to connect/pair with this device successfully. The 'MainActivity' activity has a 'get data' button to read the data from the load sensor but anytime It is pressed the app freezes. I have been told by the author of the following tutorial that I need to write some 'Handler' method. I have made an attempt with no luck.
I've been following this tutorial but I'm stuck on reading data
https://wingoodharry.wordpress.com/2014/04/15/android-sendreceive-data-with-arduino-using-bluetooth-part-2/
Here is my code :
package com.proj.splate;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
#SuppressWarnings("unused")
public class MainActivity extends Activity {
Button btnscan;
TextView txtArduino, txtString, txtStringLength, calorie;
Handler bluetoothIn;
final int handlerState = 0; //used to identify handler message
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket; //= null;
private StringBuilder recDataString = new StringBuilder();
private ConnectedThread mConnectedThread;
// SPP UUID service - this should work for most devices
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// String for MAC address
private static String address;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Link the buttons and textViews to respective views
btnscan = (Button) findViewById(R.id.scanBtn);
txtString = (TextView) findViewById(R.id.txtString);
txtStringLength = (TextView) findViewById(R.id.testView1);
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
recDataString.append(readMessage);
int endOfLineIndex = recDataString.indexOf("~");
if (endOfLineIndex > 0) {
String dataInPrint = recDataString.substring(0, endOfLineIndex);
txtString.setText("Data Received = " + dataInPrint);
int dataLength = dataInPrint.length();
txtStringLength.setText("String Length = " + String.valueOf(dataLength));
if (recDataString.charAt(0) == '#')
{
//get sensor value from string between indices 1-20
String weight = recDataString.substring(1, 20);
//update the textviews with sensor values
calorie.setText(weight + "kg");
}
recDataString.delete(0, recDataString.length());
// strIncom =" ";
dataInPrint = " ";
}
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
// Set up onClick listeners for button to scan for data
btnscan.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mConnectedThread.write("0");
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
return device.createRfcommSocketToServiceRecord(BTMODULEUUID);
//creates secure outgoing connecetion with BT device using UUID
}
#Override
public void onResume() {
super.onResume();
//Get MAC address from DeviceListActivity via intent
Intent intent = getIntent();
//Get the MAC address from the DeviceListActivty via EXTRA
address = intent.getStringExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
//create device and set the MAC address
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_LONG).show();
}
// Establish the Bluetooth socket connection.
try
{
btSocket.connect();
} catch (IOException e) {
try
{
btSocket.close();
} catch (IOException e2)
{
//insert code to deal with this
}
}
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
//I send a character when resuming.beginning transmission to check device is connected
//If it is not an exception will be thrown in the write method and finish() will be called
mConnectedThread.write("x");
}
#Override
public void onPause()
{
super.onPause();
try
{
//Don't leave Bluetooth sockets open when leaving activity
btSocket.close();
} catch (IOException e2) {
//insert code to deal with this
}
}
//Checks that the Android device Bluetooth is available and prompts to be turned on if off
private void checkBTState() {
if(btAdapter==null) {
Toast.makeText(getBaseContext(), "Device does not support bluetooth", Toast.LENGTH_LONG).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
//create new class for connect thread
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//creation of the connect thread
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
//Create I/O streams for connection
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = mmInStream.read(buffer);
bluetoothIn.obtainMessage(handlerState, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
//write method
public void write(String input) {
byte[] msgBuffer = input.getBytes();//converts entered String into bytes
try {
mmOutStream.write(msgBuffer);//write bytes over BT connection via outstream
} catch (IOException e) {
//if you cannot write, close the application
Toast.makeText(getBaseContext(), "Connection Failed", Toast.LENGTH_LONG).show();
finish();
}
}
public class BluetoothInHandler extends Handler{
private Looper sLooper = null;
private Handler mWorkerThreadHandler;
final int handlerState = 0; //used to identify handler message
protected class WorkerArgs {
Handler handler;
String input;
String output;
}
public BluetoothInHandler() {
super();
synchronized (BluetoothInHandler.class) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncWorker");
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = new WorkerHandler(sLooper);
}
#Override
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
WorkerArgs args = (WorkerArgs) msg.obj;
String readMessage = args.output;
//your job;
} else {
super.handleMessage(msg);
}
}
public void write(String input) {
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.input = input;
Message message = mWorkerThreadHandler.obtainMessage(handlerState);
message.obj = args;
mWorkerThreadHandler.sendMessage(message);
}
protected class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
WorkerArgs args = (WorkerArgs) msg.obj;
byte[] buffer;
//the code here run in a thread, not in the ui thread
//do your job like:
byte[] bytes = mmInStream.read(buffer);
args.output = new String(bytes);
Message message = args.handler.obtainMessage(handlerState);
message.obj = args;
message.sendToTarget();
}
}
}
}
}//ConnectedThread End
}
Here is my Arduino Code:
#include <LiquidCrystal.h>
int led = 13;
int button = 12;
LiquidCrystal lcd(9, 8, 4, 5, 6, 7);
// Pins used for inputs and outputs********************************************************
float sensorValue1;
float containerValue;
char inbyte = 0;
int flag;
const int numReadings = 50;
int readings[numReadings];
int index = 0;
int total = 0;
int average = 0;
//*******************************************************************************************
void setup()
{
pinMode(led, OUTPUT);
digitalWrite(led, HIGH);
Serial.begin(9600);
for (int thisReading = 0; thisReading < numReadings; thisReading++)
{
readings[thisReading] = 0;
}
lcd.begin(16, 2); //change to 16, 2 for smaller 16x2 screens
lcd.clear();
lcd.print("hello, world!");
delay (1000);
lcd.clear();
delay (500);
}
void loop()
{
digitalWrite(led, HIGH);
readSensor2(); //DONE
printLCD(); //DONE
return;
sendAndroidValues();
//when serial values have been received this will be true
if (Serial.available() > 0)
{
inbyte = Serial.read();
if (inbyte == '0')
{
//LED off
digitalWrite(led, LOW);
}
if (inbyte == '1')
{
//LED on
digitalWrite(led, HIGH);
}
}
//delay by 2s. Meaning we will be sent values every 2s approx
//also means that it can take up to 2 seconds to change LED state
delay(2000);
void readSensor2()
{
total = total - readings[index];
readings[index] = analogRead(A0);
total = total + readings[index];
index = index + 1;
if (index >= numReadings)
{
index = 0;
}
average = total / numReadings;
//sensorValue1 = (analogRead(A0) - 330)* i;
//delay(200);
Serial.println(average);
delay(100);
if( digitalRead(button) == HIGH && flag == 1)
{
flag = 0;
containerValue = 0;
}
else if (digitalRead(button) == HIGH && flag != 1)
{
flag = 1; //when the button is pressed the initially sesnsor
containerValue = sensorValue1;
delay(10);
}
//Serial.println(digitalRead(button));
delay (1000);
}
//sends the values from the sensor over serial to BT module
void sendAndroidValues()
{
//puts # before the values so our app knows what to do with the data
Serial.print('#');
//for loop cycles through 4 sensors and sends values via serial
Serial.print(sensorValue1);
Serial.print('+');
//technically not needed but I prefer to break up data values
//so they are easier to see when debugging
Serial.print('~'); //used as an end of transmission character - used in app for string length
Serial.println();
delay(5000); //added a delay to eliminate missed transmissions
}
void printLCD()
{
lcd.setCursor(4, 0);
lcd.print(" GRAMS ");
lcd.setCursor(4, 1);
lcd.print(sensorValue1);
}
Not sure if this is much of a problem, since it doesn't look like you're doing a ton of work in your handleMessage(Message msg) method, but your Handler is still being created on the main thread. To use a Handler to process background messages, you'll need to pass it a separate Looper. An easy way to to do this would be to use the HandlerThread class to provide your Looper.
Once you do this, however, you'll need to post results back to your UI thread from your handleMessage(Message msg) since you can't modify UI elements (or use Toasts, see your "write" method) from threads other than the main thread (See Activity.runOnUiThread(Runnable runnable)).
Also, you're still using your "ConnectedThread" object as an object by how you're calling your methods from within your onClickListener...so it's not really doing what you're intending it to do in that regard. To verify this, use Looper.myLooper() == Looper.getMainLooper() to see which thread is currently executing. I'd advise more towards the Handler solution suggested above, and posting Runnables for execution.
Lastly, since you're ConnectedThread runs continously in a while(true) loop without pauses, this could be flooding your handler potentially as well.