I trying to replace a Bluetooth connection with a WiFi one. My original project has a PIC Microcontroller that is data logging time, date and temps as well as controlling some outputs. I wrote an app quite a while ago (3 years, and done none since!) that uses Bluetooth to send and receive data from Android to the PIC, works fine.
So far I've got a ESP8266 connected to a Pic Microcontroller, the ESP is using ESP-LINK firmware and is connected to my home network. The pic relays what is received from the ESP8266 to RealTerm so I can monitor. I've created a test app which is creating a socket and sending a byte to the PIC, which is working fine and the bytes are being received ok, code as below.
package com.example.carl.sockets;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class MainActivity extends AppCompatActivity {
private Socket socket;
private static final int SERVERPORT = 23;
private static final String SERVER_IP = "00.00.00.00"; // enter IP of ESP8266 here
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new ClientThread()).start();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
Integer i = Integer.parseInt(et.getText().toString());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
if(i > 0 && i < 255){
out.write(i);
}else{
Toast.makeText(this,"Number out of Range !",Toast.LENGTH_SHORT).show();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Once the byte is sent to the PIC it will send a Byte or Bytes back as a response. I now need to read the byte or bytes returned from the PIC and display them in a TextView. I will know how many bytes will be sent by the PIC and received by the app in advance.
I've looked at loads of code but all seem to be for separate servers and clients, and I don't want that (or do I) and can't figure this one out.
This has probably been asked before but I've spent ages looking, and any help or advice would be most appreciated.
I've now got this working and can send a byte and receive either a single byte or bytes from my PIC via WiFi to my android app.
I've created a new thread to wait for data on the input stream. My main issue was ensuring the socket was connected before starting this thread, once I had sussed that it has worked ok.
When data is received it's sent back to the main code via a handler. My handler is outputting text to my app depending what is received, the seven bytes are a temp reading and time and date. The single byte is just displayed.
My code is attached which may not be pretty !! any constructive criticism would be welcome.
package com.example.carl.sockets;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Main Activity - Sockets";
private Handler h;
private Socket socket;
private static final int SERVERPORT = 23;
private static final String SERVER_IP = "192.168.1.78"; // enter IP of ESP8266 here
private receiveData rd;
protected static final int SUCCESS_CONNECT = 0;
protected static final int NOW_DATA_RECEIVED = 1;
protected static final int ONE_BYTE_RECEIVED = 2;
private boolean connectedSocket = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new ClientThread()).start();
while(!connectedSocket){}
rd = new receiveData(socket);
rd.start();
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case SUCCESS_CONNECT:
break;
case NOW_DATA_RECEIVED:
Log.d(TAG,"Handler - In 7 bytes received");
byte[] nowData = (byte[]) msg.obj;
// process data
int tempFrac = 0;
int tempUnits = 0;
// construct time and date string, pad to 2 figures, unsigned values
String hourStr = Integer.toString(nowData[2]&0xFF);
hourStr = "00".substring(hourStr.length()) + hourStr;
String minStr = Integer.toString(nowData[3]&0xFF);
minStr = "00".substring(minStr.length()) + minStr;
String dayStr = Integer.toString(nowData[4]&0xFF);
dayStr = "00".substring(dayStr.length()) + dayStr;
String monthStr = Integer.toString(nowData[5]&0xFF);
monthStr = "00".substring(monthStr.length()) + monthStr;
String yearStr = Integer.toString(nowData[6]&0xFF);
yearStr = "00".substring(yearStr.length()) + yearStr;
String nowDataString = new String(hourStr +":" + minStr + " " + dayStr + "/" + monthStr + "/" + yearStr);
// get unsigned values
int tempMSB = nowData[0] & 0xFF;
int tempLSB = nowData[1] & 0xFF;
// add LSB and MSB
int tempVar = tempLSB + (tempMSB<<8);
// if Zero
if(tempVar == 0){
// result zero so display zero degrees
// put in text view
TextView txtData = (TextView) findViewById(R.id.textView);
txtData.setText(nowDataString + " Temp = 0.0c");
}else if(tempMSB >= 0x80){
// result negative
tempVar = (~tempVar) + 1;
tempFrac = tempVar & 0x0F;
tempFrac = tempFrac*625/1000;
tempUnits = (tempVar>>4)&0x7F;
String tempString = new String("-"+Integer.toString(tempUnits)+"."+Integer.toString(tempFrac));
// put in text view
TextView txtData = (TextView) findViewById(R.id.textView);
txtData.setText(nowDataString + " Temp = " + tempString + "c");
}else{
// result positive
tempFrac = tempVar & 0x0F;
tempFrac = tempFrac*625/1000;
tempVar = tempVar>>4;
tempUnits = tempVar & 0x7F;
String tempString = new String(Integer.toString(tempUnits)+"."+Integer.toString(tempFrac));
// put in text view
TextView txtData = (TextView) findViewById(R.id.textView);
txtData.setText(nowDataString + " Temp = " + tempString + "c");
}
break;
case ONE_BYTE_RECEIVED:
Log.d(TAG,"Handler - In 1 byte received");
byte[] recByte = (byte[]) msg.obj;
int receivedByte = (int)recByte[0];
TextView txtData = (TextView) findViewById(R.id.textView);
txtData.setText( "One Byte Received = " + Integer.toString(receivedByte));
Log.d(TAG, "In handler, one byte received = "+ Integer.toString(receivedByte));
break;
}
}
};
}
#Override
public void onPause(){
super.onPause();
try{
socket.close();
}catch(IOException e){
Log.d(TAG,"Error closing socket in on pause");
}
rd.stopRdThread();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
Integer i = Integer.parseInt(et.getText().toString());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
if (i > 0 && i < 255) {
out.write(i);
Log.d(TAG,"Byte Sending - "+ i.toString());
} else {
Toast.makeText(this, "Number out of Range !", Toast.LENGTH_SHORT).show();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
if(socket.isConnected()){
Log.d(TAG, "in ClientThread - socket connected");
connectedSocket = true;
}else{
Log.d(TAG, "in ClientThread - socket not connected");
connectedSocket = false;
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
class receiveData extends Thread {
private Socket socketLocal;
private volatile boolean exit = false;
DataInputStream in;
byte[] fullBuffer = new byte[7];
byte[] buffer = new byte[100];
int bytes; // bytes returned from read()
int bytesCount = 0;
// constructor
receiveData(Socket socket){
this.socketLocal = socket;
}
public void run(){
try {
if (socketLocal.isConnected()) {
Log.d(TAG, "In receiveData, Socket connected");
in = new DataInputStream(socketLocal.getInputStream());
}
}catch(Exception e){
Log.d(TAG, "in receiveData - run exception - " + e.toString());
}
while(!exit){
try {
if (socketLocal.isConnected()) {
if (in.available() > 0) {
//input = in.readByte(); // Get number of bytes and message in "buffer"
bytes = in.read(buffer);
Log.d(TAG,"Bytes Read = "+Integer.toString(bytes));
System.arraycopy(buffer,0,fullBuffer,bytesCount,bytes);
bytesCount = bytesCount + bytes;
if(bytesCount >= 7){
h.obtainMessage(NOW_DATA_RECEIVED, bytesCount, -1, fullBuffer).sendToTarget(); // Send to message queue Handler
Log.d(TAG,"In handler, 7 bytes Message sent");
bytesCount = 0;
}else if(bytesCount == 1){
h.obtainMessage(ONE_BYTE_RECEIVED, bytesCount, -1, fullBuffer).sendToTarget();
Log.d(TAG, "In handler, 1 byte message sent");
bytesCount = 0;
}
}
}else{
break;
}
}catch(Exception e){
Log.d(TAG, "Read Error - " + e.toString());
}
}
}
public void stopRdThread(){
exit = true;
try {
socketLocal.close();
}catch(Exception e){
Log.d(TAG, "error closing socket - " + e.toString());
}
}
}
}
The only issue I now have is a memory leak, I think ?
I'm getting a message -
07-30 17:46:01.154 15417-15445/com.example.carl.sockets D/dalvikvm: GC_FOR_ALLOC freed 512K, 22% free 9692K/12332K, paused 18ms, total 18ms
The monitor is showing I'm using 9.4 MB once the app starts.
I sorted the leak, it was the in.available() that I was using to test if data is there for some reason. Don't really understand that! Got rid of the two if() statements in the receiveData and it works great now.
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)
}
In my mobile robot project, which have 2 servo motors to rotate the camera in two planes I want to control them in my android app by rotation the smartphone (through readings yaw/pitch/roll from the smartphone accelometer).
For that I have to send data about this three angles through Bluetooth to Arduino. So for example sample data packet looks like
"Y:100,P:20,R:45"
where [Y-yaw, P-pitch,R-roll]. However, when I try to send this kind of data packet through Bluetooth from my smartphone to Arduino, in Arduino the packet is received bit by bit, so above shown data packet in Serial Port Monitor looks like:
Y
:
1
0
0
etc. (which makes it much harder to read this data and their correct acquisition, because my smartphone sends as well other data to control the direction of mobile robot [engines]).
So if I using smartphone + Bluetooth + Arduino -> it is possible to send a whole packet of data at once, no bit by bit ???
This is the code from Android Studio (about Bluetooth Activity):
package com.samplecompass;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
public class cBluetooth{
public final static String TAG = "BL_4WD";
private static BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private ConnectedThread mConnectedThread;
// SPP UUID service
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final Handler mHandler;
public final static int BL_NOT_AVAILABLE = 1; // ������ ��� Handler
public final static int BL_INCORRECT_ADDRESS = 2;
public final static int BL_REQUEST_ENABLE = 3;
public final static int BL_SOCKET_FAILED = 4;
public final static int RECIEVE_MESSAGE = 5;
cBluetooth(Context context, Handler handler){
btAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = handler;
if (btAdapter == null) {
mHandler.sendEmptyMessage(BL_NOT_AVAILABLE);
return;
}
}
public void checkBTState() {
if(btAdapter == null) {
mHandler.sendEmptyMessage(BL_NOT_AVAILABLE);
} else {
if (btAdapter.isEnabled()) {
Log.d(TAG, "Bluetooth ON");
} else {
mHandler.sendEmptyMessage(BL_REQUEST_ENABLE);
}
}
}
public void BT_Connect(String address) {
Log.d(TAG, "...On Resume...");
if(!BluetoothAdapter.checkBluetoothAddress(address)){
mHandler.sendEmptyMessage(BL_INCORRECT_ADDRESS);
return;
}
else{
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.d(TAG, "In onResume() and socket create failed: " + e.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
btAdapter.cancelDiscovery();
Log.d(TAG, "...Connecting...");
try {
btSocket.connect();
Log.d(TAG, "...Connection ok...");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
Log.d(TAG, "In onResume() and unable to close socket during connection failure" + e2.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
}
// Create a data stream so we can talk to server.
Log.d(TAG, "...Create Socket...");
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.d(TAG, "In onResume() and output stream creation failed:" + e.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
mConnectedThread = new ConnectedThread();
mConnectedThread.start();
}
}
public void BT_onPause() {
Log.d(TAG, "...On Pause...");
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
Log.d(TAG, "In onPause() and failed to flush output stream: " + e.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
}
if (btSocket != null) {
try {
btSocket.close();
} catch (IOException e2) {
Log.d(TAG, "In onPause() and failed to close socket." + e2.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
}
}
public void sendData(String message) {
byte[] msgBuffer = message.getBytes();
Log.i(TAG, "Send data: " + message);
if (outStream != null) {
try {
outStream.write(msgBuffer);
} catch (IOException e) {
Log.d(TAG, "In onResume() and an exception occurred during write: " + e.getMessage());
mHandler.sendEmptyMessage(BL_SOCKET_FAILED);
return;
}
} else Log.d(TAG, "Error Send data: outStream is Null");
}
/**
public void write(byte[] bytes) {
try {
outStream.write(bytes);
} catch (IOException e) { System.out.println(e); }
}
**/
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
public ConnectedThread() {
InputStream tmpIn = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = btSocket.getInputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
}
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);
mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
}
}
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.
I'm trying to build an android app that loops 5 MAC addresses because there's 5 devices being used but not at the same time but with the same functions.
Currently I'm using this to start the string:
private static String address = "00:06:66:0A:AD:98";
And this to connect that address to the bluetooth adapter:
BluetoothDevice device = btAdapter.getRemoteDevice(address);
I'm a bit of a noob but the rest of the app is working. It sends and receives data from a serial and displays it in a simple fashion.
Any help would be appreciated.
I've attached the whole code for your review, it's based off a tutorial.
package com.example.bluetooth2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
import com.example.bluetooth2.R;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String TAG = "Arduino controller";
Button btnOn, btnOff, btnQ, btnTurbo;
TextView txtArduino,txtOther;
Handler h;
final int RECIEVE_MESSAGE = 1; // Status for Handler
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder sb = new StringBuilder();
private ConnectedThread mConnectedThread;
// SPP UUID service
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// MAC-address of Bluetooth module (you must edit this line)
private static String address = "00:06:66:0A:AD:98";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnQ = (Button) findViewById(R.id.btnQ); // button baton status
btnOn = (Button) findViewById(R.id.btnOn); // button LED ON
btnOff = (Button) findViewById(R.id.btnOff); // button LED OFF
btnTurbo = (Button) findViewById(R.id.btnTurbo); // button TURBO
txtArduino = (TextView) findViewById(R.id.txtArduino); // display battery life
txtOther = (TextView) findViewById(R.id.txtOther); // display other information
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
String[] parts = sbprint.split(" "); // split string
String batteryLife = parts[0]; // battery
String otherInfo = parts[1]; // other
sb.delete(0, sb.length()); // and clear
txtArduino.setText(batteryLife); // update TextView
txtOther.setText(otherInfo); // update textOther
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
btnOn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
btnOn.setEnabled(false);
btnTurbo.setEnabled(true);
btnOff.setEnabled(true);
mConnectedThread.write("h"); // Send "1" via Bluetooth
//Toast.makeText(getBaseContext(), "Turn on LED", Toast.LENGTH_SHORT).show();
}
});
btnOff.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
btnOff.setEnabled(false);
btnTurbo.setEnabled(true);
btnOn.setEnabled(true);
mConnectedThread.write("l"); // Send "0" via Bluetooth
//Toast.makeText(getBaseContext(), "Turn off LED", Toast.LENGTH_SHORT).show();
}
});
btnQ.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mConnectedThread.write("?"); // Send "0" via Bluetooth
//Toast.makeText(getBaseContext(), "Baton Status", Toast.LENGTH_SHORT).show();
}
});
btnTurbo.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
btnOff.setEnabled(true);
btnTurbo.setEnabled(false);
btnOn.setEnabled(true);
mConnectedThread.write("t"); // Send "t" via Bluetooth
//Toast.makeText(getBaseContext(), "Turbo mode", Toast.LENGTH_SHORT).show();
}
});
}
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) {
Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
}
return device.createRfcommSocketToServiceRecord(MY_UUID);
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "...onResume - try connect...");
// Set up a pointer to the remote node using it's address
Log.d(TAG, "...onResume - try connect...");
// 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) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
// 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.
Log.d(TAG, "...Connecting...");
try {
btSocket.connect();
Log.d(TAG, "....Connection ok...");
} 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.
Log.d(TAG, "...Create Socket...");
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "...In 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) {
errorExit("Fatal Error", "Bluetooth not support");
} else {
if (btAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth ON...");
} else {
//Prompt user to turn on Bluetooth
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) {
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() + "...");
}
}
}
}
String[] fiveMacAddresses = {"address1", "address2", "address3", "address4", "address5"};
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(fiveMacAddresses.length);
for (String address: fiveMacAddresses) {
devices.add(btAdapter.getRemoteDevice(address));
}
now you have array of devices.
I'm developing an Android application which includes Bluetooth SPP Connection. The post on Receiving String from RFCOMM on PC, sent from Android really helped me.
Even my log in Eclipse says 'wrote 6 bytes out of 6' many times and then the socket gets closed. But, I want to receive (whatever I sent) in my PC using Hyperterminal. How do I do that? How to specify Virtual COM Port in code?
I'm using a Samsung SGH-T759 for testing in USB Debugging mode.
Here's my code:
public class BluetoothActivity extends Activity {
private int bluetooth = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
TextView text = (TextView) findViewById(R.id.text);
text.setText("Click on the button to access devices through Bluetooth");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_bluetooth, menu);
return true;
}
public void bluetoothActivate(View view) {
int REQUEST_ENABLE_BT = 1;
int RESULT_ENABLE_BT = 0;
//TextView text = (TextView) findViewById(R.id.text);
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
System.out.println("Button clicked...");
if (mBluetoothAdapter == null) {
//txtView.setText("This device does not support Bluetooth");
CharSequence txt = "This device does not support Bluetooth";
Toast toast = Toast.makeText(getApplicationContext(), txt, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
else {
//CharSequence text = "Bluetooth is supported!!!";
System.out.println("Bluetooth is supported!!!");
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
onActivityResult(REQUEST_ENABLE_BT, RESULT_ENABLE_BT, enableBtIntent);
}
else
bluetooth = 1;
device_access(view);
}
}
public void device_access(View view) {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
TextView text = (TextView) findViewById(R.id.text);
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
Spinner btDevices = (Spinner) findViewById(R.id.btDevices);
System.out.println("Bluetooth devices...");
if (bluetooth == 1)
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
System.out.println("Bluetooth paired devices...");
final ArrayAdapter<CharSequence> mArrayAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_list_item_1);
ArrayAdapter<CharSequence> deviceName = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_list_item_1);
mArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
deviceName.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
deviceName.add(device.getName());
}
btDevices.setVisibility(1);
btDevices.setAdapter(mArrayAdapter);
//txtView.append("\nPaired Bluetooth Devices Found...");
/*// Create a BroadcastReceiver for ACTION_FOUND
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
*/
String[] dvc = btDevices.getSelectedItem().toString().split("\n");
final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //UUID for serial connection
String mac = "90:00:4E:DC:41:9D"; //my laptop's mac adress
//mac = dvc[1];
text.append("\n Data sent to " + btDevices.getSelectedItem().toString());
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mac); //get remote device by mac, we assume these two devices are already paired
// Get a BluetoothSocket to connect with the given BluetoothDevice
BluetoothSocket socket = null;
OutputStream out = null;
InputStream inp = null;
//try {
//socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
Method m;
try {
m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(device, 1);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//}catch (IOException e) {}
try {
mBluetoothAdapter.cancelDiscovery();
socket.connect();
out = socket.getOutputStream();
inp = socket.getInputStream();
//now you can use out to send output via out.write
String outputValue = "Hi...\n",inputValue;
byte[] op = outputValue.getBytes(),buffer = null;
int inpBytes;
for (int i=0; i<1000000; i++) {
out.write(op);
out.flush();
}
System.out.println("Data written!!");
/*while (true) {
try {
// Read from the InputStream
inpBytes = inp.read(buffer);
inputValue = buffer.toString();
text.append(inpBytes+ " " + inputValue);
} catch (IOException e) {
}
}*/ }catch (IOException e) {} finally {
try {
socket.close();
System.out.println("Socket closed...");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
I myself solved it. I had to use the listenUsingRfcommWithServiceRecord(NAME,SERIAL_UUID) to register my phone's SPP capability on my laptop. Then, my laptop assigned a COM port for SPP communication with my phone. Then, I specified this port in AccessPort137 (another application similar to hyperterminal and better than that in some aspects) and established communication properly. My working code follows:
package com.example.bluetoothtest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.UUID;
import com.example.bluetoothtest.R;
import com.example.bluetoothtest.DynamicGraph;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class BluetoothActivity extends Activity {
public final static String EXTRA_MESSAGE = "com.example.bluetoothtest.MESSAGE";
public int bluetooth = 0, mState = 0;
public boolean runThread = false;
private TextView text;
public static final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //UUID for serial connection
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_CONNECTED = 1;
public static final int MESSAGE_READ = 2;
public static final int START_INTENT = 3;
public static final int REQ_CODE_DYNAMIC = 4;
public static BluetoothAdapter mBluetoothAdapter = null;
public static BluetoothDevice device = null;
BluetoothServerSocket mmServerSocket = null;
BluetoothSocket socket = null,finalSocket = null;
OutputStream out = null;
//InputStream aStream = null;
InputStreamReader aReader = null;
BufferedReader mBufferedReader = null;
ConnectedThread con = null;
AcceptThread accept = null;
ConnectThread connect = null;
Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
if (con != null) {con.cancel(); con = null;}
mState = STATE_DISCONNECTED;
// Start the thread to listen on a BluetoothServerSocket
if (accept!= null) {
accept = null;
}
text = (TextView) findViewById(R.id.text);
text.setText("Click on the button to access devices through Bluetooth");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_bluetooth, menu);
return true;
}
#Override
public void onDestroy(){
super.onDestroy();
runThread = false;
}
public void bluetoothActivate(View view) {
int REQUEST_ENABLE_BT = 1;
int RESULT_ENABLE_BT = 0;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
System.out.println("Button clicked...");
if (mBluetoothAdapter == null) {
CharSequence txt = "This device does not support Bluetooth";
Toast toast = Toast.makeText(getApplicationContext(), txt, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
else {
System.out.println("Bluetooth is supported!!!");
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
onActivityResult(REQUEST_ENABLE_BT, RESULT_ENABLE_BT, enableBtIntent);
}
else
bluetooth = 1;
device_access(view);
}
}
public void bluetoothDisconnect(View view) {
runThread = false;
con.cancel();
//connect.cancel();
System.out.println("Connection disconnected");
text.append("\n Connection disconnected");
}
public void device_access(View view) {
System.out.println("Bluetooth devices...");
if (bluetooth == 1) {
//String mac = "F0:08:F1:36:D3:5B"; //my other phone's mac adress
String mac = "90:00:4E:DC:41:9D"; //my laptop's mac adress
//String mac = "A0:4E:04:B8:1D:62";
//mac = dvc[1];
//text.append("\n Data sent to " + btDevices.getSelectedItem().toString());
//device = mBluetoothAdapter.getRemoteDevice(mac); //get remote device by mac, we assume these two devices are already paired
//text.append("device = " + device);
text.append("\n Bluetooth started...");
System.out.println("Bluetooth Started...");
//ensureDiscoverable();
String backup_file = "dynamic_bluetooth.csv";
intent = new Intent(this, DynamicGraph.class);
intent.putExtra(EXTRA_MESSAGE, backup_file);
System.out.println("Dynamic intent about to start...");
/*connect = new ConnectThread(device);
connect.start();*/
CheckBox plotGraph = (CheckBox) findViewById(R.id.plotGraph);
if (plotGraph.isChecked())
startActivityForResult(intent,REQ_CODE_DYNAMIC);
else {
accept = new AcceptThread();
accept.start();
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
this.mmDevice = device;
BluetoothSocket tmp1 = null;
try {
tmp1 = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmSocket = tmp1;
}
#Override
public void run() {
setName("ConnectThread");
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
System.out.println("Connected with the device");
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
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 void ensureDiscoverable() {
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
System.out.println("Device set discoverable");
text.append("\n Device set discoverable");
return;
}
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);*/
//float readM = Float.parseFloat(readMessage);
System.out.println("Into handler...");
String readMessage = (String) msg.obj;
text.append("\n" + readMessage);
try{
float readM = Float.parseFloat(readMessage);
text.append(" " + readM);
}catch (NumberFormatException e) {
text.append(" - Number Format Exception!!");
e.printStackTrace();
}
break;
case START_INTENT:
System.out.println("Dynamic intent about to start...");
//startActivityForResult(intent,REQ_CODE_DYNAMIC);
break;
}
}
};
private class AcceptThread extends Thread {
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
System.out.println("Listening...");
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("SPP", SERIAL_UUID);
}catch (IOException e) {
System.out.println("Listening Failed");
}
mmServerSocket = tmp;
if (mmServerSocket != null)
System.out.println("Server socket established: tmp = " + tmp);
else
System.out.println("Server socket NOT established: tmp = " + tmp);
}
public void run() {
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
//socket = mmServerSocket.accept();
System.out.println("AcceptThread Run");
while (true) {
if ((mmServerSocket != null) && (mState != STATE_CONNECTED)) {
try {
socket = mmServerSocket.accept();
device = socket.getRemoteDevice();
} catch (IOException e) {
System.out.println("Socket not received");
break;
}
if (socket!= null) {
System.out.println("Device Address: " + device.getAddress());
runThread = true;
con = new ConnectedThread(socket);
con.start();
mState = STATE_CONNECTED;
break;
}
}
else {
System.out.println("Code incomplete. Repeat Listening");
break;
}
}
}
finally {
/*try {
con.cancel();
mmServerSocket.close();
System.out.println("Socket closed...");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Server Socket close problem...");
e.printStackTrace();
} */
}
}
public void cancel() {
try {
mmServerSocket.close();
accept.start();
} catch (IOException 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) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024],readBuffer = new byte[1024];
int bytesAvailable,readBufferPosition;
char[] readMsg = new char[8192];
/*try {
aStream = socket.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("InputStream problem...");
e.printStackTrace();
}*/
/*aReader = new InputStreamReader( mmInStream );
mBufferedReader = new BufferedReader( aReader );*/
String aString = "---";
System.out.println("Waiting for input...");
/*try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
System.out.println("Sleeping problem...");
e1.printStackTrace();
}*/
while (runThread) {
try {
/*aReader = new InputStreamReader( mmInStream );
mBufferedReader = new BufferedReader( aReader );
//aString = mBufferedReader.readLine();
mBufferedReader.read(readMsg);
aString = new String(readMsg);
readMsg = new char[8192];
System.out.println(aString);*/
aString = "---";
byte delimiter = 'N'; //New line
readBuffer = new byte[1024];
readBufferPosition = 0;
bytesAvailable = mmInStream.read(buffer);
boolean copied = false;
if (bytesAvailable > 0)
System.out.println(bytesAvailable + " bytes available");
else
System.out.println("Bytes not available");
for(int i=0;i<bytesAvailable;i++)
{
byte b = buffer[i];
System.out.println("Byte = "+ b);
if(b == delimiter)
{
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
aString = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
copied= true;
break;
}
else
{
readBuffer[readBufferPosition++] = b;
}
}
/*aString = new String(buffer);
aString = aString.trim();*/
//float rx_data = Float.parseFloat(aString);
System.out.println("aString = " + aString);
/*mHandler.obtainMessage(BluetoothActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();*/
//buffer = new byte[1024];
if (copied && (aString != "---"))
mHandler.obtainMessage(BluetoothActivity.MESSAGE_READ, aString)
.sendToTarget();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("mBufferedReader problem...");
e.printStackTrace();
break;
}
}
//cancel();
/*out = socket.getOutputStream();
//now you can use out to send output via out.write
String outputValue = "Hi...\n",inputValue;
byte[] op = outputValue.getBytes(),buffer = null;
int inpBytes;
for (int i=0; i<1000000; i++) {
out.write(op);
out.flush();
}
System.out.println("Data written!!");
while (true) {
try {
// Read from the InputStream
inpBytes = inp.read(buffer);
inputValue = buffer.toString();
text.append(inpBytes+ " " + inputValue);
} catch (IOException e) {
}
} */
}
public void cancel() {
try {
/*aReader.close();
mBufferedReader.close();*/
runThread = false;
mState = STATE_DISCONNECTED;
mmSocket.close();
mmServerSocket.close();
System.out.println("Socket closed in thread...");
accept = new AcceptThread();
accept.start();
} catch (IOException e) {
System.out.println("Socket close problem...");
}
}
}
}
Uncomment and run the ConnectThread also if you want bi-directional communication. I only had to receive values; so, I've commented it out. But, this thread has to be run in order to establish a COM port for your phone with your laptop. This is because, only when an application like this which uses Bluetooth SPP is run in the phone and tries to pair with the laptop (using this ConnectThread), the laptop will register the SPP capability of the phone. To see this and enable SPP from your laptop's side, do the following:
Right-click on your Bluetooth icon in the taskbar and click on 'Show Bluetooth Devices'.
In the window that opens, find your phone (remember that it must already be paired with your laptop before even running this SPP application), right-click it and go to 'Properties'.
Go to the 'Services' tab and you'll find a new entry called by the name that you provide as the first parameter in the listenUsingRfcommWithServiceRecord() method. For me it's 'SPP'.
Check that new service to enable SPP between your laptop and your phone.
Now, if you check the 'Hardware' tab, a COM port will be specified which you can use in HyperTerminal or any such application and start communicating.
Also, remember that this is NOT possible with Windows 8 yet! Whatever I've mentioned here pertains to Windows 7; I haven't done this in Windows XP even though it will be pretty much the same method.
I hope my solution helps! And, I welcome comments on my (novice) code from experts in these things - after all, I guess StackOverflow is primarily for that purpose.