【问题标题】:Android sending command via bluetooth failedAndroid通过蓝牙发送命令失败
【发布时间】:2014-07-12 06:11:15
【问题描述】:

我将实现从我的 Android 平板电脑向嵌入了蓝牙 IC 芯片 Andrino HC-06 的电子设备发送命令的模块,用于通过蓝牙配置我的设备。在执行方面,发送22 23 54 01 C8 时似乎没有来自设备的可观察响应。 它显示以下超时异常 预计设备将重新启动并返回许多消息。将这些 eta 命令发送到我的设备进行远程控制时,我应该了解更多信息?

日志猫消息

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)

下面是我的代码

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);
        }
    }

发送命令

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();
        }
    }

【问题讨论】:

  • 首先,获取设备文档,它让您知道设备的蓝牙模式,它是主设备还是从设备,以及所有其他信息,如任何 ACK、数据包和命令。如果是主设备,只需打开一个服务器来监听传入的连接,如果是从设备,只需连接到该设备。但首先要配对设备。
  • 您可以参考安卓示例中的btchat应用。我使用此方法将十六进制字符串转换为字节数组: public static byte[] hexStringToByteArray(String s) { int len = s.length();字节[] 数据 = 新字节[len / 2]; for (int i = 0; i

标签: android bluetooth command


【解决方案1】:

我想设备已经配对并且 android 设备执行发现。 为什么你认为这是一个超时问题?异常告诉通信套接字已经关闭。也许您成功创建了一个BluetoothSocket 并“意外”关闭它(也许在刷新之后,您关闭了与套接字相关的输出或输入流)。

由于您正在关注 Android BluetoothChat 示例,您应该:

1) 执行发现并侦听可用设备:

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) 连接设备:

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) 检索输入和输出流以与配对设备通信(在需要通信时不要关闭流):

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
    }
}

InsecureBluetooth 类用于“避免”配对阶段,它基于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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-08
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 2019-05-16
    相关资源
    最近更新 更多