将Android设备连接到多个蓝牙串行嵌入式对等设备

时间:2012-04-14 02:15:38

标签: android bluetooth iobluetooth

我正在尝试为此设置找到解决方案:

我有一个Android设备,我想连接到多个串行嵌入式设备......

这就是使用“正常”方式检索蓝牙套接字的方法,并不适用于所有设备,虽然它可以,但我可以连接到多个设备,并从多个设备发送和接收数据设备。

public final synchronized void connect()
        throws ConnectionException {
    if (socket != null)
        throw new IllegalStateException("Error socket is not null!!");
    connecting = true;
    lastException = null;
    lastPacket = null;
    lastHeartBeatReceivedAt = 0;
    log.setLength(0);
    try {
        socket = fetchBT_Socket_Normal();
        connectToSocket(socket);
        listenForIncomingSPP_Packets();
        connecting = false;
        return;
    } catch (Exception e) {
        socket = null;
        logError(e);
    }
    try {
        socket = fetchBT_Socket_Workaround();
        connectToSocket(socket);
        listenForIncomingSPP_Packets();
        connecting = false;
        return;
    } catch (Exception e) {
        socket = null;
        logError(e);
    }
    connecting = false;
    if (socket == null)
        throw new ConnectionException("Error creating RFcomm socket for" + this);
}

private BluetoothSocket fetchBT_Socket_Normal()
        throws Exception {
    /* The getType() is a hex 0xXXXX value agreed between peers --- this is the key (in my case) to multiple connections in the "Normal" way */
    String uuid = getType() + "1101-0000-1000-8000-00805F9B34FB";

    try {
        logDebug("Fetching BT RFcomm Socket standard for UUID: " + uuid + "...");
        socket = btDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
        return socket;
    } catch (Exception e) {
        logError(e);
        throw e;
    }
}

private BluetoothSocket fetchBT_Socket_Workaround()
        throws Exception {
    Method m;
    int connectionIndex = 1;
    try {
        logDebug("Fetching BT RFcomm Socket workaround index " + connectionIndex + "...");
        m = btDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
        socket = (BluetoothSocket) m.invoke(btDevice, connectionIndex);
        return socket;
    } catch (Exception e1) {
        logError(e1);
        throw e1;
    }
}

private void connectToSocket(BluetoothSocket socket)
        throws ConnectionException {
    try {
        socket.connect();
    } catch (IOException e) {
        try {
            socket.close();
        } catch (IOException e1) {
            logError("Error while closing socket", e1);
        } finally {
            socket = null;
        }
        throw new ConnectionException("Error connecting to socket with" + this, e);
    }
}

这就是问题,而在“正常”方式不起作用的手机上,“解决方法”方式为单个连接提供了解决方案。我searched far and wide,但想出了拉链。

在最后一个链接中提到了变通方法的问题,两个连接使用相同的端口,在我的情况下,导致一个块,其中两个嵌入式设备实际上可以发送数据,而不是在Android上处理,而两个嵌入式设备都可以接收从Android发送的数据。

以前有人处理过吗?

还有一些参考here

更新

关注this(我之前发布的)我想给mPort一个机会,也许看看其他端口索引,以及其他设备如何管理它们,我发现了BluetoothSocket对象中的字段在两种情况下它们都是相同的类FQN:

来自HTC Vivid 2.3.4的Detils,使用“解决方法”技术:

Socket类的类型是:[ android.bluetooth.BluetoothSocket ]

mSocket BluetoothSocket  (id=830008629928)  
    EADDRINUSE          98  
    EBADFD              77  
    MAX_RFCOMM_CHANNEL  30  
    TAG                 "BluetoothSocket" (id=830002722432) 
    TYPE_L2CAP          3   
    TYPE_RFCOMM         1   
    TYPE_SCO            2   
    mAddress            "64:9C:8E:DC:56:9A" (id=830008516328)   
    mAuth               true    
    mClosed             false   
    mClosing            AtomicBoolean  (id=830007851600)    
    mDevice             BluetoothDevice  (id=830007854256)  
    mEncrypt            true    
    mInputStream        BluetoothInputStream  (id=830008688856) 
    mLock               ReentrantReadWriteLock  (id=830008629992)   
    mOutputStream       BluetoothOutputStream  (id=830008430536)    
    **mPort             1** 
    mSdp                null    
    mSocketData         3923880 
    mType               1   

来自LG-P925 2.2.2的Detils使用“普通”技术:

Socket类的类型是:[ android.bluetooth.BluetoothSocket ]

mSocket BluetoothSocket  (id=830105532880)  
    EADDRINUSE          98  
    EBADFD              77  
    MAX_RFCOMM_CHANNEL  30  
    TAG                 "BluetoothSocket" (id=830002668088) 
    TYPE_L2CAP          3   
    TYPE_RFCOMM         1   
    TYPE_SCO            2   
    mAccepted           false   
    mAddress            "64:9C:8E:B9:3F:77" (id=830105544600)   
    mAuth               true    
    mClosed             false   
    mConnected          ConditionVariable  (id=830105533144)    
    mDevice             BluetoothDevice  (id=830105349488)  
    mEncrypt            true    
    mInputStream        BluetoothInputStream  (id=830105532952) 
    mLock               ReentrantReadWriteLock  (id=830105532984)   
    mOutputStream       BluetoothOutputStream  (id=830105532968)    
    mPortName           "" (id=830002606256)    
    mSocketData         0   
    mSppPort            BluetoothSppPort  (id=830105533160) 
    mType               1   
    mUuid               ParcelUuid  (id=830105714176)   

任何人都有一些见解......

1 个答案:

答案 0 :(得分:0)

哇,每次这个让一个大型WTF击倒我的时候?

这是一个竞争条件问题,它明显适用于一个版本的android,而不是另一个版本。在Android对等端,我正在解析从套接字收到的数据包:

public class SocketListener
        implements Runnable {

    private boolean stop;

    private OnIncomingPacketListener packetListener;

    @Override
    public void run() {
        InputStream inputStream;
        try {
            stop = false;
            inputStream = socket.getInputStream();
            while (!stop) {
                Packet packet = Packet.getPacket(inputStream);
                lastPacket = packet;
                if (packet.getDescriptor() == Packet.HeartBeat)
                    lastHeartBeatReceivedAt = System.currentTimeMillis();
                else if (packet.getDescriptor() == Packet.LogEntry)
                    log.append(((LogEntryPacket) packet).getLogEntry());
                synchronized (this) {
                    if (packetListener != null)
                        packetListener.onIncomingData(EmbeddedDevice.this, packet);
                }
            }
        } catch (IOException e) {
            logError("----- BLUETOOTH IO ERROR -----\n @: " + EmbeddedDevice.this, e);

            return;
        } catch (RuntimeException e) {
            logError("----- BLUETOOTH LISTENER ERROR -----\n @: " + EmbeddedDevice.this, e);
            throw e;
        } finally {
            socketListeningThread = null;
        }
    }
}

Packet.getPacket(inputStream)的位置是:

public static synchronized Packet getPacketInstance(InputStream inputStream)
        throws IOException {
    int data = inputStream.read();
    Packet type = null;
    for (Packet packetType : values())
        if (packetType.packetType == data) {
            type = packetType;
            break;
        } // race condition here...
    if (type == null)
        throw new IllegalArgumentException("Unknown packet type: " + data);
    try {
        Packet packet = type.incomingPacketType.newInstance();
        packet.setDescriptor(type);
        packet.readPacketData(inputStream);
        return packet;
    } catch (IOException e) {
        throw e;
    } catch (Exception e) {
        throw new IllegalStateException("Error instantiating type: " + type.incomingPacketType.getName(), e);
    }

}

每次数据包完成时,下一个线程都应该进行解析。

我的猜测是端口上存在某种锁定,与我的实现一起导致第二个线程无限期地阻塞,一旦我将每个线程的解析移除到不同的实例,问题就解散了。

这种见解的灵感来自 Daniel Knoppel ,来自 mPort 链接的人。

谢谢丹尼尔!