在android中通过BLE传输图像 [英] Transfer Image throug BLE in android

查看:41
本文介绍了在android中通过BLE传输图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下代码传输 1 mb 的图像.如果在每个数据包之间实现了线程延迟,则图像传输成功.如果未设置线程延迟,则所有数据包均从 BluetoothGattServer 发送,但 BluetoothGattCallback 未收到所有数据包.

I'm transfering an image of 1 mb using the following code. The image gets transferred successfully if a thread delay is implemented between each packets. If the thread delay is not set all the packets are sent from BluetoothGattServer but the BluetoothGattCallback does not receive all the packets.

谁能指导在没有线程延迟的情况下发送数据包

Can anyone guide in sending the packets without the thread delay

在每个数据包之间实现线程

Implement thread between each packets

private void sendingContinuePacket(BluetoothGattCharacteristic characteristic,
                                   byte[] CHARACTERS) {
    boolean isComplete = false;
    runOnUiThread(() -> {
        tv_status.setText("Sending Data...!!");
        startTime = SystemClock.uptimeMillis();
        customHandler.postDelayed(updateTimerThread, 0);
    });

    // Check the data length is large how many times with Default Data (BLE)

    int times = CHARACTERS.length / DEFAULT_BYTES_IN_CONTINUE_PACKET;
    totalPackets = times;
    Log.i("", "CHARACTERS.length() " + CHARACTERS.length);

    byte[] packetNoByte;
    byte[] sending_continue_hex = new byte[DEFAULT_BYTES_IN_CONTINUE_PACKET];
    for (int time = 0; time <= times; time++) {

        final int remainingTime = time;
        if (!hasDisconnected) {
            this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mRelativeLayout.setVisibility(View.VISIBLE);
                    if (totalPackets != 0) {
                        showProgress(totalPackets, remainingTime);
                    }
                }
            });
        } else {
            runOnUiThread(() -> {
                mProgressBar.setProgress(0);
                tv_progress.setText(0 + "%");
                tv_timer.setText("00:00:00");
                tv_imageSize.setText("");
                tv_status.setText("");
                Toast.makeText(PeripheralRoleActivity.this, "Something went wrong, Please Try again", Toast.LENGTH_SHORT).show();
                customHandler.removeCallbacks(updateTimerThread);
            });
            return;
        }
        int a;
        int b;

        /**
         * @param THREAD_SLEEP_TIME_FOR_NOTIFICATION
         * this delay is placed to give a small pause while sending the data packe
         * */
        try {
            Thread.sleep(Constants.THREAD_SLEEP_TIME_FOR_NOTIFICATION);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sentPacket = sentPacket + 1;
        byte[] packetArray = Utils.getUtilsClass().toByteArray(sentPacket);
        packetNoByte = Arrays.copyOf(packetArray, packetArray.length);

        if (time == times) {
            Log.i("", "LAST PACKET ");
            int character_length = CHARACTERS.length
                    - DEFAULT_BYTES_IN_CONTINUE_PACKET * times;
            byte[] sending_last_hex = new byte[character_length];
            a = (sending_continue_hex.length) * time;
            b = a + character_length;
            if(b-a ==0){
                return;
            }
            sending_last_hex = Arrays.copyOfRange(CHARACTERS, a, b);

            byte[] last_packet =
                    new byte[packetNoByte.length + character_length];
            System.arraycopy(packetNoByte, 0, last_packet,
                    0, packetNoByte.length);
            System.arraycopy(sending_last_hex, 0, last_packet,
                    packetNoByte.length, sending_last_hex.length);


            Log.d("Sending packets", Arrays.toString(last_packet));
            // Set value for characteristic
            characteristic.setValue(last_packet);
            notifyCharacteristicChanged();
            isComplete = true;
            customHandler.removeCallbacks(updateTimerThread);
            currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
            Log.d("Collection", "End Time: " + currentDateTimeString);
            Utils.getUtilsClass().sendNotification(getApplicationContext(), "Data Transfer", "Transfer Complete");


        } else {

            Log.i("", "CONTINUE PACKET ");

            a = ((sending_continue_hex.length) * time);
            b = a + DEFAULT_BYTES_IN_CONTINUE_PACKET;

            sending_continue_hex = Arrays.copyOfRange(CHARACTERS, a, b);


            byte[] sending_continue_packet =
                    new byte[packetNoByte.length + sending_continue_hex.length];
            System.arraycopy(packetNoByte, 0, sending_continue_packet,
                    0, packetNoByte.length);
            System.arraycopy(sending_continue_hex, 0, sending_continue_packet,
                    packetNoByte.length, sending_continue_hex.length);


            Log.d("data transfer a", String.valueOf(a));
            Log.d("data transfer b", String.valueOf(b));
            Log.d("data trans bytes", String.valueOf(sending_continue_hex.length));
            if(output == null){
                output = new ByteArrayOutputStream();
            }
            try {
                if {
                    characteristic.setValue(sending_continue_packet);
                    Log.d("Sending packets", Arrays.toString(sending_continue_packet));
                    notifyCharacteristicChanged();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        Log.d("Data byte", "times " + time);

        if (isComplete) {
            characteristic.setValue("Completed");
            notifyCharacteristicChanged();
        }
        runOnUiThread(() -> tv_status.setText("Data sent!!"));
    }
}

更新代码

//下面的函数用于将图像字节[]拆分成数据包并存储在一个数组列表中

//the following function is used break the image byte [] into packets and store it in an arraylist

private void breakPackets(byte[] CHARACTERS) {
        // Check the data length is large how many times with Default Data (BLE)

        int times = CHARACTERS.length / DEFAULT_BYTES_IN_CONTINUE_PACKET;
        totalPackets = times;
        packetList = new ArrayList<>();
        sendingPacket = 0;
        Log.i("", "CHARACTERS.length() " + CHARACTERS.length);


        byte[] sending_continue_hex = new byte[DEFAULT_BYTES_IN_CONTINUE_PACKET];
        for (int time = 0; time <= times; time++) {


            int a;
            int b;

            if (time == times) {
                Log.i("", "LAST PACKET ");
                int character_length = CHARACTERS.length
                        - DEFAULT_BYTES_IN_CONTINUE_PACKET * times;
                byte[] sending_last_hex = new byte[character_length];
                a = (sending_continue_hex.length) * time;
                b = a + character_length;

                sending_last_hex = Arrays.copyOfRange(CHARACTERS, a, b);
                //packetList is an ArrayList<byte[]>
                packetList.add(sending_last_hex);
                startSendingPackets(sendingPacket);
            } else {
                a = (sending_continue_hex.length) * time;
                b = a + DEFAULT_BYTES_IN_CONTINUE_PACKET;
                sending_continue_hex = Arrays.copyOfRange(CHARACTERS, a, b);

                packetList.add(sending_continue_hex);
            }
            Log.d("Data byte", "times " + time);

        }
    }

    //the following function is used to set the byte[] from the arraylist to the characteristics and then notify the characteristics
     private void startSendingPackets(int packet) {
        isCommand = false;
        mSampleCharacteristic.setValue(packetList.get(packet));
        notifyCharacteristicChanged();
        Log.i("packeting", "Sending  ------------> " + packet);
    }


    /*************************************************/



     @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            //check if status is success
            if (status == BluetoothGatt.GATT_SUCCESS) {
            //if status is not successful isExecutable is false and the else loop is executed to resend the same packet that has failed
                if (isExecutable) {
//                    Log.i("packeting", "Sent  ------------> " + sendingPacket);
                    sendingPacket = sendingPacket + 1;
                    int size = packetList.size();
                    if (sendingPacket <= size-1) {

                        startSendingPackets(sendingPacket);

                        Log.d(MainActivity.TAG, "Notification sent. Status: " + status + " sending packet no --" + sendingPacket);
                    } else {
                        sendCommand("Completed");
                    }
                } else {
                    startSendingPackets(sendingPacket);
                    isExecutable = true;
                    Log.d(MainActivity.TAG, "Notification sent. Status: " + status + " sending packet no --" + sendingPacket);
                }
            }else{
            //if status is not successful
                isExecutable = false;

                Log.d(MainActivity.TAG, "Notification sent. fail Status: " + status );
            }


        }

推荐答案

可以在 https://developer.android.com/reference/android/bluetooth/BluetoothGattServerCallback.html#onNotificationSent(android.bluetooth.BluetoothDevice,%20int):

当要发送多个通知时,应用程序必须等待在发送额外的之前接收这个回调通知.

When multiple notifications are to be sent, an application must wait for this callback to be received before sending additional notifications.

这意味着在您调用了 notifyCharacteristicChanged 之后,您不能再次调用 notifyCharacteristicChanged,直到收到回调 onNotificationSent.因此,您需要删除 for 循环并重构您的代码以遵循 API 规则.

This means after you have called notifyCharacteristicChanged, you cannot call notifyCharacteristicChanged again until the callback onNotificationSent has been received. So you need to remove your for-loop and refactor your code to follow the API rules.

这样做的原因是为了获得流量控制.如果您只是以比 BLE 链路的吞吐量更快的速度推送新数据包,则内部缓冲区会变满,并且会发生数据包丢失.这就是为什么延迟似乎有效,但它不是一个可靠的解决方案,这就是为什么您应该等待 onNotificationSent 回调,因为这意味着 BLE 堆栈已准备好接受新数据包.

The reason for this is to get flow control. If you just push new packets faster than the BLE link's throughput, the internal buffers get full and packet loss will occur. That's why a delay might seem to work, but it's not a robust solution so that's why you should wait for the onNotificationSent callback since that means the BLE stack is ready to accept new packets.

这篇关于在android中通过BLE传输图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆