问题
I am going to implement the module of sending commands from my Android tablet to electronic device embedded with Bluetooth IC-chips Andrino HC-06 , for configuration of my device via Bluetooth. When it comes to execution, it seems that there is no observable response from the device when sending 22 23 54 01 C8.
It show the following timeout exception
It is expected that the device will restart and return many messages. What should I know more about when sending these eta commands to my device for remote control ?
The log cat message
05-23 18:19:44.866: E/BluetoothChatService(512): java.io.IOException: bt socket closed, read return: -1
05-23 18:19:44.866: E/BluetoothChatService(512): at android.bluetooth.BluetoothSocket.read(BluetoothSocket.java:429)
05-23 18:19:44.866: E/BluetoothChatService(512): at android.bluetooth.BluetoothInputStream.read(BluetoothInputStream.java:96)
05-23 18:19:44.866: E/BluetoothChatService(512): at java.io.InputStream.read(InputStream.java:162)
05-23 18:19:44.866: E/BluetoothChatService(512): at com.example.android.BluetoothChat.BluetoothChatService$ConnectedThread.run(BluetoothChatService.java:485)
The below is my code
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
.show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
Sending Commands
public void write(byte[] buffer) {
try {
boolean connected = false;
BluetoothSocket sock = null;
InputStream in = null ;
OutputStream out = null ;
BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:14:01:12:28:12");
Method m = zee.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
sock = (BluetoothSocket) m.invoke(zee, Integer.valueOf(1));
sock.connect();
in = sock.getInputStream();
out = sock.getOutputStream();
char[] test = { 0x22 , 0x21 , 0x03 , 0x00 , 0xc9};
for(int k=0; k < test.length; k++){
new DataOutputStream(sock.getOutputStream()).writeByte(test[k]);
}
byte [] bfferX = new String(test).getBytes("UTF-8");*/
mmOutStream.write(buffer);
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
回答1:
I suppose the device are already paired and that the android device performs the discovery. Why do you think it is a matter of timeout? The exception tells that the communication socket is already closed. Maybe you succeed in create a BluetoothSocket and close it "accidentally" (maybe, after flushing, you close the output or input stream related to the socket).
Since you are following the Android BluetoothChat example you should:
1) perform the discovery and listen for available devices:
private final BroadcastReceiver deviceFoundBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action) && mState==STATE_DISCOVERING) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
new ConnectThread(device).start();
}
}
};
2) connect to the device:
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
private BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = InsecureBluetooth.createRfcommSocketToServiceRecord(mmDevice, YOUR_UUID, false);
}
catch (IOException e) { }
mmSocket = tmp;
}
@Override
public void run() {
try {
btAdapter.cancelDiscovery(); // be sure discovery is cancelled
mmSocket.connect(); // blocking call, returns only on a successful connection or an exception
connected(mmSocket, mmSocket.getRemoteDevice());
new ConnectedThread(mmSocket, mmDevice.getAddress()).start(); // start connected thread
}
catch (IOException e) {}
}
public void cancel() {}
}
3) Retrieve the input and output stream for communicating with the paired device (do not close the streams while communication is needed):
private class ConnectedThread extends Thread {
private BluetoothSocket mmSocket;
private String macAddress;
public ConnectedThread(BluetoothSocket socket, String macAddress) {
this.macAddress = macAddress;
this.mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
}
catch (IOException e) {}
}
@Override
public void run() {
// perform communication
}
}
The class InsecureBluetooth is used to "avoid" the pairing phase and is based on this Stanford peace of code:
@TargetApi(10)
public class InsecureBluetooth {
static private class InUse extends RuntimeException { }
public static BluetoothServerSocket listenUsingRfcommWithServiceRecord(BluetoothAdapter adapter, String name, UUID uuid, boolean encrypt) throws IOException {
if(Build.VERSION.SDK_INT<10) {
try {
Class c_rfcomm_channel_picker = null;
Class[] children = BluetoothAdapter.class.getDeclaredClasses();
for(Class c : children) {
Log.e("TO", "class " + c.getCanonicalName());
if(c.getCanonicalName().equals(BluetoothAdapter.class.getName() + ".RfcommChannelPicker")) {
c_rfcomm_channel_picker = c;
break;
}
}
if(c_rfcomm_channel_picker == null)
throw new RuntimeException("can't find the rfcomm channel picker class");
Constructor constructor = c_rfcomm_channel_picker.getDeclaredConstructor(UUID.class);
if(constructor == null)
throw new RuntimeException("can't find the constructor for rfcomm channel picker");
Object rfcomm_channel_picker = constructor.newInstance(new Object[] {uuid});
Method m_next_channel = c_rfcomm_channel_picker.getDeclaredMethod("nextChannel", new Class[] {});
m_next_channel.setAccessible(true);
BluetoothServerSocket socket = null;
int channel;
int errno;
while (true) {
channel = (Integer)m_next_channel.invoke(rfcomm_channel_picker, new Object[] {});
if (channel == -1) {
throw new IOException("No available channels");
}
try {
socket = listenUsingRfcomm(channel, encrypt);
break;
} catch(InUse e) {
continue;
}
}
Field f_internal_service = adapter.getClass().getDeclaredField("mService");
f_internal_service.setAccessible(true);
Object internal_service = f_internal_service.get(adapter);
Method m_add_rfcomm_service_record = internal_service.getClass().getDeclaredMethod("addRfcommServiceRecord", new Class[] {String.class, ParcelUuid.class, int.class, IBinder.class});
m_add_rfcomm_service_record.setAccessible(true);
int handle = (Integer)m_add_rfcomm_service_record.invoke(internal_service, new Object[] { name, new ParcelUuid(uuid), channel, new Binder() } );
if (handle == -1) {
try {
socket.close();
} catch (IOException e) {}
throw new IOException("Not able to register SDP record for " + name);
}
Field f_internal_handler = null;
try {
f_internal_handler = adapter.getClass().getDeclaredField("mServiceRecordHandler");
} catch(Exception e) {
f_internal_handler = adapter.getClass().getDeclaredField("mHandler");
}
f_internal_handler.setAccessible(true);
Object internal_handler = f_internal_handler.get(adapter);
Method m_set_close_handler = socket.getClass().getDeclaredMethod("setCloseHandler", new Class[] {Handler.class, int.class});
m_set_close_handler.setAccessible(true);
m_set_close_handler.invoke(socket, new Object[] { internal_handler, handle});
return socket;
} catch (Exception e) {}
}
else {
return adapter.listenUsingInsecureRfcommWithServiceRecord(name, uuid);
}
}
private static BluetoothServerSocket listenUsingRfcomm(int port, boolean encrypt, boolean reuse) throws IOException, InUse {
BluetoothServerSocket socket = null;
try {
Constructor<BluetoothServerSocket> constructor = BluetoothServerSocket.class.getDeclaredConstructor(int.class, boolean.class, boolean.class, int.class);
if(constructor == null)
throw new RuntimeException("can't find the constructor");
constructor.setAccessible(true);
Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
f_rfcomm_type.setAccessible(true);
int rfcomm_type = (Integer)f_rfcomm_type.get(null);
Field f_e_addr_in_use = BluetoothSocket.class.getDeclaredField("EADDRINUSE");
f_e_addr_in_use.setAccessible(true);
int e_addr_in_use = (Integer)f_e_addr_in_use.get(null);
socket = constructor.newInstance(new Object[] { rfcomm_type, false, encrypt, port } );
Field f_internal_socket = socket.getClass().getDeclaredField("mSocket");
f_internal_socket.setAccessible(true);
Object internal_socket = f_internal_socket.get(socket);
Method m_bind_listen = internal_socket.getClass().getDeclaredMethod("bindListen", new Class[] {});
m_bind_listen.setAccessible(true);
Object result = m_bind_listen.invoke(internal_socket, new Object[] {});
int errno = (Integer)result;
if(reuse && errno == e_addr_in_use) {
throw new InUse();
} else if (errno != 0) {
try {
socket.close();
} catch (IOException e) {}
internal_socket.getClass().getMethod("throwErrnoNative", new Class[] {int.class}).invoke(internal_socket, new Object[] { errno });
}
return socket;
} catch (Exception e) {}
}
public static BluetoothServerSocket listenUsingRfcomm(int port, boolean encrypt) throws IOException {
return listenUsingRfcomm(port, encrypt, false);
}
private static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, int port, UUID uuid, boolean encrypt) throws IOException {
try {
BluetoothSocket socket = null;
Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
int.class, int.class, boolean.class, boolean.class, BluetoothDevice.class, int.class, ParcelUuid.class);
if(constructor == null)
throw new RuntimeException("can't find the constructor for socket");
constructor.setAccessible(true);
Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
f_rfcomm_type.setAccessible(true);
int rfcomm_type = (Integer)f_rfcomm_type.get(null);
socket = constructor.newInstance(new Object[] { rfcomm_type, -1, false, true, device, port, uuid != null ? new ParcelUuid(uuid) : null} );
return socket;
} catch (Exception e) {}
}
public static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, UUID uuid, boolean encrypt) throws IOException{
if(Build.VERSION.SDK_INT<10) {
return createRfcommSocketToServiceRecord(device, -1, uuid, encrypt);
}
else {
return device.createInsecureRfcommSocketToServiceRecord(uuid);
}
}
public static BluetoothSocket createRfcommSocket(BluetoothDevice device, int port, boolean encrypt) throws IOException {
return createRfcommSocketToServiceRecord(device, port, null, encrypt);
}
}
来源:https://stackoverflow.com/questions/23819817/android-sending-command-via-bluetooth-failed