如何在Xamarin Forms中分割和发送超过20字节的数据到BLE?

4

我正在尝试在Xamarin forms中实现BLE。我想要发送的数据大于20字节。我已经看过使用Java的本机Android实现,它看起来像下面这样:

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 you do not have enough characters to send continue packet,
                 * This is the last packet that 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 you have enough characters to send continue packet,
                 * This is the continue packet that 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;
            }
        }
    }

这是我的Xamarin 代码,其中我执行写操作。
 private async Task<string> ReadAndWriteCharacterisicsValue(ICharacteristic _characteristics)
        {
            if (_characteristics != null)
            {
                var sbnew = new StringBuilder("BLE Characteristics\n");
                byte[] senddata = Encoding.UTF8.GetBytes(string.IsNullOrEmpty("") ? "Hi1290004847846767627723676" : "");

                if (MainThread.IsMainThread)
                {
                    string writeTypes = _characteristics.WriteType.ToString();
                    await _characteristics.WriteAsync(senddata);

                }

                //_characteristics.ReadAsync();


                var charVal = _characteristics.Value;

                var str = Encoding.UTF8.GetString(charVal);
                sbnew.AppendLine($"Characteristics found on this device: {string.Join(", ", str.ToString())}");

                return sbnew.ToString();


            }
            return null;
        }

当我尝试发送字符串Hi1290004847846767627723676(27 Bytes)时,但在外设没有崩溃的情况下得到Hi129000484784676762(20 Bytes)。 我正在使用plugin.ble最新版本,并且我的蓝牙设备版本为5.0我甚至尝试请求Mtu。如下代码所示:

 if (_characteristics != null)
            {
                try
                {

                    var sbnew = new StringBuilder("BLE Characteristics\n");
                     byte[] senddata = Encoding.UTF8.GetBytes(string.IsNullOrEmpty("") ? "Start{'command':'UnSelectEnhancement','data':[{'UnSelectEnhancement':'VitaminC'},{'UnSelectEnhancement':'CitricAcid'},  {'UnSelectEnhancement':'Electolytes'},{'UnSelectEnhancement':'Sweetener'}]}End":"");
                   
                    await _device.RequestMtuAsync(2000);
                  

                    
                    if (MainThread.IsMainThread)
                    {
                        string writeTypes = _characteristics.WriteType.ToString();
                         await _characteristics.WriteAsync(senddata);

                    }

我希望发送最多200字节的数据。我还尝试使用此代码拆分字符串

IEnumerable<string> s = str.Split();
                    IEnumerable<string> Split( )
                    {
                        while (!string.IsNullOrWhiteSpace(str))
                        {
                            var chunk = str.Take(size).ToArray();
                           str = str.Substring(chunk.Length);
                           yield return new string(chunk);

                       }

                    }

                    
                    Console.WriteLine("Error of split");
                    
                    Console.WriteLine(String.Join(Environment.NewLine, str));
                    Console.WriteLine(String.Join(Environment.NewLine, str));

但是它没有起作用。对我来说看起来相当复杂。是否有更简单的方法在xamarin forms中使用c#进行数据写入操作,以处理大于20字节的数据


1
你使用的是哪个版本的BLE?4.2+可以在一条消息中发送超过20个字节。 - Michael Kotzjan
1
插件应至少支持4.2的所有功能,如果可以的话更好。BLE版本取决于您设备的BLE版本。所有现代智能手机都至少支持v4.2。要使用v4.2的功能,外围设备也需要支持4.2。如果是这种情况,您应该能够请求更高的MTU以发送更大的消息。 - Michael Kotzjan
1
我明白了。将MTU设置为更高的值可以解决这个问题,而不需要分割您的数据。 - Michael Kotzjan
1
请查看您插件中的此讨论:https://github.com/xabre/xamarin-bluetooth-le/issues/128,以及此 Android 函数:https://learn.microsoft.com/en-us/dotnet/api/android.bluetooth.bluetoothgatt.requestmtu?view=xamarin-android-sdk-9 - Michael Kotzjan
2
我只能假设2000太大了。尝试一些现实的东西,比如251,这是BLE 4.2的最大值。如果这不起作用,我就没有更多线索了。 - Michael Kotzjan
显示剩余13条评论
1个回答

3
你可以尝试将数据拆分为多个块,每个块不超过20个字节。 这个示例先发送20个字节的第一个块,然后再发送剩下的7个字节。
            byte[] senddata = Encoding.ASCII.GetBytes("Hi1290004847846767627723676");
            int start = 0;
            while (start < senddata.Length)
            {
                int chunkLength = Math.Min(20, senddata.Length - start);
                byte[] chunk = new byte[chunkLength];
                Array.Copy(senddata, start, chunk, 0, chunkLength);
                await writeBuf.WriteAsync(chunk);
                start += 20;
            }

编辑:

  • 删除了复制粘贴的评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接