public class BluetoothMain { private boolean isConnected = false ; private volatile boolean hasDataToSend = false ; private volatile boolean hasDataToReceive = false ; private boolean isScaning = false ; private boolean isNeedConnect = false ; // 用在回调函数中,当连接状态断开后,判断是否是正常断开还是需要重连 private HandlerThread handlerThread = null ; private Handler handler = null ; private Runnable runnable = null ; // XXX 关于定时器和计数器的时间计数设置需要重新设定 private Counter dataTransferCounter = null ; private Counter readCounter = null ; // this counter is to process read failed so many times private Counter writeAfterReadCounter = null ; // this counter is to process write failed so many times after successful read private Counter ackConfirmCounter = null ; // this counter is to prevent infinitely read characteristic after writing an ack private java.util.Timer timer = null ; // 主要用于连接失败时进行尝试 private BluetoothManager bleManager = null ; private BluetoothAdapter mAdapter = null ; private BluetoothAdapter.LeScanCallback mLeScanCallback = null ; private BluetoothGattCallback gattCallback = null ; private BluetoothGatt bluetoothGatt = null ; private Context context = null ; private BLECallback bleCallback = null ; private byte bleRssi = 0 ; private byte scanCount = 0 ; private byte connectCount = 0 ; private short postTime = 0 ; private static final boolean DBG = true ; private static final String BLUETOOTH_INFO = "bluetoothComm" ; public BluetoothMain(Context context, List<String> deviceUUIDList, BLECallback bleCb) { this .context = context; bleCallback = bleCb; bleUUIDList = deviceUUIDList; bleManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); mAdapter = bleManager.getAdapter(); deviceFoundSet = new HashSet<String>(); deviceLoseMap = new ConcurrentHashMap<String, Boolean>(); deviceInControlSet = new HashSet<String>(); activeDevices = new HashSet<String>(); sleepDevices = new HashSet<String>(); dataSendUuidQueue = new HashMap<String, Queue< byte []>>(); mLeScanCallback = new LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte [] scanRecord) { bleRssi = ( byte ) rssi; String bleAddress = device.getAddress(); String deviceUUID = FrameUtility.convertMACToUUID(bleAddress); if (scanRecord[ 7 ] == GattConstants.ADVERTISE_TYPE_SLEEP){ // 判断设备是否是处于休眠状态,然后更新设备所在的集合(活跃设备、休眠设备) if ( activeDevices.contains(deviceUUID)){ activeDevices.remove(deviceUUID); } sleepDevices.add(deviceUUID); } else { if ( sleepDevices.contains(deviceUUID)){ sleepDevices.remove(deviceUUID); } activeDevices.add(deviceUUID); // 小节点处于活跃状态 if (scanRecord[ 7 ] == GattConstants.ADVERTISE_TYPE_COMMON) { // 小节点没有数据发送,根据deviceUUID查看dataSendUUIDList中是否有数据需要发送 if (dataSendUuidQueue.get(deviceUUID) != null && dataSendUuidQueue.get(deviceUUID).size() > 0 ){ if (firstScanToSend) { firstScanToSend = false ; hasDataToSend = true ; connect(bleAddress); } } } else if (scanRecord[ 7 ] == GattConstants.ADVERTISE_TYPE_DATA) { // 小节点有数据需要发送 if (firstScanToReceive) { firstScanToReceive = false ; connect(bleAddress); } } } } }; gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super .onConnectionStateChange(gatt, status, newState); if (status == BluetoothGatt.GATT_SUCCESS){ if (DBG){Log.d(BLUETOOTH_INFO, "onConnectionStateChange ---> operation success" );} if (newState == BluetoothGatt.STATE_DISCONNECTED) { if (!isConnected) { if (!isNeedConnect) { // 正常断开 if (DBG){Log.d(BLUETOOTH_INFO, "onConnectionStateChange ---> disconnected" );} } } else { // 意外断开后直接断开,不尝试重连 if (DBG){Log.d(BLUETOOTH_INFO, "onConnectionStateChange ---> disconnected acidentally" );} isConnected = false ; firstScanToSend = true ; firstScanToReceive = true ; } if (bluetoothGatt != null ){ bluetoothGatt.close(); // 释放资源 bluetoothGatt = null ; } //断开连接,开始扫描。经测试,不能直接调用startSearch(),否则会有10s的延时。 //另外,若立即开始扫描的话,由于蓝牙节点的广播切换需要时间,可能还会扫描到"02"广播包,导致不必要的连接。 handler.postDelayed(runnable, 400 ); } else if (newState == BluetoothGatt.STATE_CONNECTED) { isConnected = true ; isNeedConnect = false ; if (timer != null ){ timer.cancel(); timer = null ; } // 进行服务发现,50ms try { Thread.sleep( 50 ); } catch (Exception e) { e.printStackTrace(); } gatt.discoverServices(); } } else { if (DBG){Log.d(BLUETOOTH_INFO, "onConnectionStateChange ---> operation failure" );} } } @Override public void onServicesDiscovered( final BluetoothGatt gatt, int status) { super .onServicesDiscovered(gatt, status); BluetoothGattService service = gatt.getService(UUID.fromString(GattConstants.SERVICE_UUID)); BluetoothGattCharacteristic readCharacteristic_2 = service.getCharacteristic(UUID.fromString(GattConstants.CHARACTERISTIC_READ_UUID_2)); gatt.readCharacteristic(readCharacteristic_2); } @Override public void onCharacteristicRead( final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) { super .onCharacteristicRead(gatt, characteristic, status); byte [] data = characteristic.getValue(); BluetoothGattService service = gatt.getService(UUID.fromString(GattConstants.SERVICE_UUID)); BluetoothGattCharacteristic writeCharacteristic_1 = service.getCharacteristic(UUID.fromString(GattConstants.CHARACTERISTIC_WRITE_UUID_1)); final String deviceUuid = FrameUtility.convertMACToUUID(gatt.getDevice().getAddress()); // 手机向小节点发送数据是通过写特征值1来实现的,当小节点读取完数据之后,将特征值设为全1 if (characteristic.equals(writeCharacteristic_1)) { // 读特征值1操作成功 if (status == BluetoothGatt.GATT_SUCCESS) { // 小节点读取完毕,关闭超时计数器,继续发送下一个数据 if (isArrayEqual(data, GattConstants.FrameInfo.ALL_ONE_RSP.getBytes())) { if (readCounter != null ) { readCounter.close(); readCounter = null ; } dataSendUuidQueue.get(deviceUuid).poll(); sendNextPacket(); } else { // 小节点未将数据取走,计数器加1 if (readCounter == null ) { // 连续读取10次失败之后,断开连接,回到初始状态 readCounter = new Counter( 10 , "readCounter" , new CounterTask() { @Override public void run() { readCounter.close(); readCounter = null ; // sendNextPacket(); dataSendUuidQueue.get(deviceUuid).poll(); //由于PC和服务器端存在重传机制,超时之后删除当前数据包,并断开连接 disconnect(); } }); readCounter.start(); } readCounter.addCount(); if (readCounter.getCount() <= readCounter.getMaxCount()) { gatt.readCharacteristic(characteristic); } } } else { // CQ:实验中测试,程序到达这里之后,连接会断开然后自动重新连接 if (DBG){Log.d(BLUETOOTH_INFO, "onCharacteristicRead status---> failed" );} } } else { // 读特征值2(用于小节点向手机发送数据) if (status == BluetoothGatt.GATT_SUCCESS) { // 如果读到的数据为全0,表示小节点没有数据要发送 if (isArrayEqual(data, GattConstants.FrameInfo.ALL_ZERO_RSP.getBytes())) { // XXX 不使用计数器,若没有数据则直接断开 if (ackConfirmCounter != null ) { ackConfirmCounter.close(); ackConfirmCounter = null ; } hasDataToReceive = false ; if (hasDataToSend) { sendNextPacket(); } else { // 手机没有数据要发送 disconnect(); } } else if (isArrayEqual(data, GattConstants.FrameInfo.ALL_ONE_RSP.getBytes())) { hasDataToReceive = false ; if (hasDataToSend) { sendNextPacket(); } else { // 手机没有数据要发送 if (DBG){Log.d(BLUETOOTH_INFO, "disconnect ---> no data to send" );} disconnect(); } } else { // 小节点有数据发送过来 if (ackConfirmCounter != null ) { ackConfirmCounter.close(); ackConfirmCounter = null ; } hasDataToReceive = true ; if (data[GattConstants.FrameInfo.FRAME_HEX_MAX_LEN] == '1' ) { // 最后一个字节为'1',表示小节点还有数据需要发送 characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); characteristic.setValue(GattConstants.FrameInfo.ALL_ONE_RSP.getBytes()); gatt.writeCharacteristic(characteristic); } else if (data[GattConstants.FrameInfo.FRAME_HEX_MAX_LEN] == '0' ) { // 最后一个字节为'0',表示小节点没有数据需要发送 hasDataToReceive = false ; // CQ:读完最后一个数据包之后,将特征值全部置0,表示这一个阶段结束 characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); characteristic.setValue(GattConstants.FrameInfo.ALL_ZERO_RSP.getBytes()); gatt.writeCharacteristic(characteristic); } // 对读取到的数据包进行转义,然后调用回调接口向上层发送数据 String uuid = FrameUtility.convertMACToUUID(bluetoothGatt.getDevice().getAddress()); byte [] dataToServer = FrameUtility.decodeFrame(data, true , uuid.getBytes(),( byte )-bleRssi); //printData(dataToServer, "data to server"); bleCallback.dataReceivedCb(dataToServer); } } } } |