【问题标题】:How to split and send data >20 bytes for BLE in Xamarin forms?如何在 Xamarin 表单中为 BLE 拆分和发送 >20 字节的数据?
【发布时间】:2020-12-19 01:21:30
【问题描述】:

我正在尝试在 Xamarin 表单中实现 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 字节) 时,我在外围设备没有崩溃得到 Hi129000484784676762(20 字节)。我正在使用 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 表单中使用 c# 对大于 20 字节的数据进行写入操作

【问题讨论】:

  • 您使用的是哪个版本的 BLE? 4.2+ 允许在一条消息中发送超过 20 个字节
  • 插件应该至少支持 4.2 的所有功能,如果不是更多的话。 BLE 版本取决于您设备的 BLE 版本。所有现代智能手机都至少支持 v4.2。要使用 v4.2 的功能,外设也需要支持 4.2。如果是这种情况,您应该能够要求更高的 MTU 来发送更大的消息
  • 这可能是 MTU 设置为 20 造成的。我快速浏览了一下,但在 Plugin.BLE 中没有发现任何允许请求更高 MTU 的内容。
  • 我明白了。将 MTU 设置为更高的值可以在不拆分数据的情况下解决该问题。
  • 我只能假设 2000 太大了。尝试一些现实的东西,比如 251,BLE 4.2 的最大值。如果这不起作用,我就没有更多线索了

标签: java c# android xamarin.forms bluetooth-lowenergy


【解决方案1】:

您可以尝试以多个块的形式发送数据,每个块的最大大小为 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;
            }

编辑:

  • 删除了复制粘贴的评论

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 2017-05-24
    • 2015-09-09
    • 2017-05-29
    • 2013-11-30
    • 1970-01-01
    相关资源
    最近更新 更多