Android:通过BLE发送数据> 20个字节
通过连接到外部BLE设备,我可以发送多达20个字节的数据。 如何发送大于20个字节的数据。 我已经读过,我们必须要分割数据或分割特征到所需的部分。 如果我假设我的数据是32字节,你能告诉我的变化,我需要在我的代码使这个工作吗? 以下是我的代码所需的片段:
public boolean send(byte[] data) { if (mBluetoothGatt == null || mBluetoothGattService == null) { Log.w(TAG, "BluetoothGatt not initialized"); return false; } BluetoothGattCharacteristic characteristic = mBluetoothGattService.getCharacteristic(UUID_SEND); if (characteristic == null) { Log.w(TAG, "Send characteristic not found"); return false; } characteristic.setValue(data); characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); return mBluetoothGatt.writeCharacteristic(characteristic); }
这是我用来发送数据的代码。 “发送”function用于以下onclick事件。
sendValueButton = (Button) findViewById(R.id.sendValue); sendValueButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String text = dataEdit.getText().toString(); yableeService.send(text.getBytes()); } });
当String text
大于20字节时,只接收前20个字节。 如何纠正这一点?
要testing发送多个特征,我试过这个:
sendValueButton = (Button) findViewById(R.id.sendValue); sendValueButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String text = "Test1"; yableeService.send(text.getBytes()); text = "Test2"; yableeService.send(text.getBytes()); text = "Test3"; yableeService.send(text.getBytes()); } });
但是我只收到了“Test3”即最后一个特征。 我犯了什么错误? 我是BLE的新手,所以请忽略任何天真
编辑:
之后接受任何人的答复 。
有两种方法可以做到这一点。 1.分解你的数据,并按照选定的答案进行循环写入。 2.分解你的数据,并使用callback,即onCharacterisitcWrite()
写入。 如果在写作过程中有任何错误,这样可以避免错误。
但是,如果只写入并且不等待来自固件的响应,写入之间最重要的是使用Thread.sleep(200)
。 这将确保您的所有数据到达。 没有sleep
我总是得到最后一包。 如果你注意到接受的答案,他也曾经在两者之间使用过sleep
。
BLE允许你最多传输20个字节。
如果你想发送更多的20个字节,你应该定义数组byte []包含你想要的数据包。
如果要发送<160个字符(160个字节),示例工作正常。
p / s:让编辑按照你想要的。 没有跟着我。
实际上,当我们使用BLE时,移动端和固件端需要设置Key(例如0x03 …)来定义双方的连接门。
这个想法是:
-
当我们仍然继续传送数据包时,不是最后一个。 门是
byte[1] = 0x01
。 -
如果我们发送最后一个,门是
byte[1] = 0x00
。
数据结构(20字节):
1 – Byte 1
– 定义Gate ID
:例如 信息门ID byte[0] = 0x03
。
2 – Byte 2
– 定义recognization
:最后一个数据包是0x00
还是继续发送数据包0x01
。
3 – Byte 3
(应该是减去Byte 1
和Byte 2
后的18个Byte 2
) – 在这里附加消息内容。
请在阅读下面的代码之前了解我的逻辑。
下面是关于发送带有许多数据包的消息的例子,每个数据包:byte [20]。
private void sendMessage(BluetoothGattCharacteristic characteristic, String CHARACTERS){ byte[] initial_packet = new byte[3]; /** * Indicate byte */ initial_packet[0] = BLE.INITIAL_MESSAGE_PACKET; if (Long.valueOf( String.valueOf(CHARACTERS.length() + initial_packet.length)) > BLE.DEFAULT_BYTES_VIA_BLE) { sendingContinuePacket(characteristic, initial_packet, CHARACTERS); } else { sendingLastPacket(characteristic, initial_packet, CHARACTERS); } } private void sendingContinuePacket(BluetoothGattCharacteristic characteristic, byte[] initial_packet, String CHARACTERS){ /** * TODO If data length > Default data can sent via BLE : 20 bytes */ // Check the data length is large how many times with Default Data (BLE) int times = Byte.valueOf(String.valueOf( CHARACTERS.length() / BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET)); Log.i(TAG, "CHARACTERS.length() " + CHARACTERS.length()); Log.i(TAG, "times " + times); // TODO // 100 : Success // 101 : Error byte[] sending_continue_hex = new byte[BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET]; for (int time = 0; time <= times; time++) { /** * Wait second before sending continue packet */ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } if (time == times) { Log.i(TAG, "LAST PACKET "); /** * If can not have enough characters to send continue packet, * This is the last packet will be sent to the band */ /** * Packet length byte : */ /** * Length of last packet */ int character_length = CHARACTERS.length() - BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET*times; initial_packet[1] = Byte.valueOf(String.valueOf(character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH)); initial_packet[2] = BLE.SENDING_LAST_PACKET; Log.i(TAG, "character_length " + character_length); /** * Message */ // Hex file byte[] sending_last_hex = new byte[character_length]; // Hex file : Get next bytes for (int i = 0; i < sending_last_hex.length; i++) { sending_last_hex[i] = CHARACTERS.getBytes()[sending_continue_hex.length*time + i]; } // Merge byte[] byte[] last_packet = new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH]; System.arraycopy(initial_packet, 0, last_packet, 0, initial_packet.length); System.arraycopy(sending_last_hex, 0, last_packet, initial_packet.length, sending_last_hex.length); // Set value for characteristic characteristic.setValue(last_packet); } else { Log.i(TAG, "CONTINUE PACKET "); /** * If have enough characters to send continue packet, * This is the continue packet will be sent to the band */ /** * Packet length byte */ int character_length = sending_continue_hex.length; /** * TODO Default Length : 20 Bytes */ initial_packet[1] = Byte.valueOf(String.valueOf( character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH)); /** * If sent data length > 20 bytes (Default : BLE allow send 20 bytes one time) * -> set 01 : continue sending next packet * else or if after sent until data length < 20 bytes * -> set 00 : last packet */ initial_packet[2] = BLE.SENDING_CONTINUE_PACKET; /** * Message */ // Hex file : Get first 17 bytes for (int i = 0; i < sending_continue_hex.length; i++) { Log.i(TAG, "Send stt : " + (sending_continue_hex.length*time + i)); // Get next bytes sending_continue_hex[i] = CHARACTERS.getBytes()[sending_continue_hex.length*time + i]; } // Merge byte[] byte[] sending_continue_packet = new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH]; System.arraycopy(initial_packet, 0, sending_continue_packet, 0, initial_packet.length); System.arraycopy(sending_continue_hex, 0, sending_continue_packet, initial_packet.length, sending_continue_hex.length); // Set value for characteristic characteristic.setValue(sending_continue_packet); } // Write characteristic via BLE mBluetoothGatt.writeCharacteristic(characteristic); } } public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic, String data) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return false; } if (ActivityBLEController.IS_FIRST_TIME) { /** * In the first time, * should send the Title */ byte[] merge_title = sendTitle(data); // Set value for characteristic characteristic.setValue(merge_title); // Write characteristic via BLE mBluetoothGatt.writeCharacteristic(characteristic); // Reset ActivityBLEController.IS_FIRST_TIME = false; return true; } else { /** * In the second time, * should send the Message */ if (data.length() <= BLE.LIMIT_CHARACTERS) { sendMessage(characteristic, data); // Reset ActivityBLEController.IS_FIRST_TIME = true; return true; } else { // Typed character typed_character = data.length(); return false; } } }
棒棒糖上最多可以发送512个字节。 您需要使用值为512的BluetoothGatt.requestMtu()
。另外,正如@Devunwired提到的,您需要等到之前的任何操作完成才能调用。
BLE规范不允许写操作超过20个字节是正确的。 如果你不能把你的有效载荷细分成多个特征(这在逻辑上会更容易维护),那么你的分块机制就是另一种方法。
然而,当你试图排队多个操作时,要意识到BLE堆栈不好 。 每个读取/写入都是asynchronous的,其结果是通过BluetoothGattCallback
实例上的onCharacteristicRead()
或onCharacteristicWrite()
callback。 你写的代码试图发送三个特征性的写操作,而不用等待两者之间的callback。 你的代码将需要遵循一个更像是的path:
send(Test1) -> Wait for onCharacteristicWrite() -> send(Test2) -> Wait for onCharacteristicWrite() -> send(Test3) -> Wait for onCharacteristicWrite() Done!
如果另一端的设备支持,您实际上可以触发BLE长写。
您可以通过将写入types设置为BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
在这种情况下,您可以发送超过20个字节。
如果你想通过BLE发送大量的数据,那么你最好的办法就是使用两个特性,一个发送大部分数据,另一个发送最后一个段。 通过这种方式,您不需要将响应设置为WRITE_NO_RESPONSE,并使用callback直接发送下一个段,直到到达最后一个段,然后将第二个特性写入第二个特性,从而让设备知道你已经完成了数据的写操作,并且它可以把所有的数据连接起来形成一个大的数据包。
这里有很多误导。
BLE能够发送超过20个字节,并且可以在android中轻松完成。
你需要改变的是默认设置为23的链路MTU(其中只有20个可以用来设置一个值)。 如果发送的给定数据包大于当前链接MTU(这是onCharacteristicRead(...)
API中offset参数的目的),则Android提供分段机制。
因此,您可以使用requestMtu(...)
API作为来自中央的请求,使MTU更大。 后者将在外围侧在onMtuChanged
上引起一个callback,通知他新的MTU。 完成此操作后,您可以发送更大的数据包,而不会发出Android碎片机制。
替代方法是build立你自己的碎片整理机制,而不是发送大于MTU的数据包。 或者依靠Android机制并使用'offset'参数进行工作。
这是使用chunk方法实现的例子,但是没有使用Thread.sleep ,我发现发送超过20位的数据对于我的应用程序来说更好,更高效。
数据包将在onCharacteristicWrite()
触发后发送。 我发现这个方法会在外围设备(BluetoothGattServer)
发送sendResponse()
方法后自动触发。
首先我们必须用这个函数把分组数据转换成块:
public void sendData(byte [] data){ int chunksize = 20; //20 byte chunk packetSize = (int) Math.ceil( data.length / (double)chunksize); //make this variable public so we can access it on the other function //this is use as header, so peripheral device know ho much packet will be received. characteristicData.setValue(packetSize.toString().getBytes()); mGatt.writeCharacteristic(characteristicData); mGatt.executeReliableWrite(); packets = new byte[packetSize][chunksize]; packetInteration =0; Integer start = 0; for(int i = 0; i < packets.length; i++) { int end = start+chunksize; if(end>data.length){end = data.length;} packets[i] = Arrays.copyOfRange(data,start, end); start += chunksize; }
我们的数据准备好之后,所以我把这个函数迭代:
@Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if(packetInteration<packetSize){ characteristicData.setValue(packets[packetInteration]); mGatt.writeCharacteristic(characteristicData); packetInteration++; } }