安卓蓝牙BLE设备通讯发送和接受超过20个字节的问题

最近做的项目是手机端和BLE设备通讯,而BLE设备又做了限制一次包只能传递20个字节的数据,多了就得分包发送,在这里记录一下如何解决这个问题。
(PS:之前链接什么的回调什么的 就不过多说了)
1.发送数据包突破20个字节。

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == GATT_SUCCESS) {
                BluetoothHelper.this.gatt = gatt;
                gatt.requestMtu(512);
                List<BluetoothGattService> services = gatt.getServices();
                for (int i = 0; i < services.size(); i++) {
                    List<BluetoothGattCharacteristic> characteristics = services.get(i).getCharacteristics();
                    if (services.get(i).getUuid().toString().contains(UUID_service_conn)) {
                        for (int j = 0; j < characteristics.size(); j++) {
                            if (characteristics.get(j).getUuid().toString().equals(UUID_write)) {
                                Log.e(TAG, "写入数据的特性UUID为" + characteristics.get(j).getUuid().toString());
                                writeBluetoothGattCharacteristic = characteristics.get(j);
                            } else if (characteristics.get(j).getUuid().toString().contains(UUID_read_conn)) {
                                Log.e(TAG, "读取数据的特性UUID为" + characteristics.get(j).getUuid().toString());
                                readBluetoothGattCharacteristic = characteristics.get(j);
                            }
                        }
                    }
                }
            }
        }

主要是这一行:

 gatt.requestMtu(512);

在发现服务的时候设置这个值,就会走后面的回调。

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
            if (BluetoothGatt.GATT_SUCCESS == status) {
                Log.e(TAG, "onMtuChanged success MTU = " + mtu);
                setBleNotification();
            } else {
                Log.e(TAG, "onMtuChanged fail " + mtu);
            }
        }

成功之后设置设备主动通知时的回调

    /**
     * 设置监听通知
     */
    public void setBleNotification() {
        if (readBluetoothGattCharacteristic != null) {
            BluetoothGattDescriptor descriptor = readBluetoothGattCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            gatt.readCharacteristic(readBluetoothGattCharacteristic);
            if (gatt.writeDescriptor(descriptor)) {
                // 蓝牙设备在数据改变时,通知App,App在收到数据后回调onCharacteristicChanged方法
                gatt.setCharacteristicNotification(readBluetoothGattCharacteristic, true);
            }
        }
    }

这样当设备端数据改变时就会回调以下方法。

 @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            }

完成以上操作就达到了每次发送数据时突破20个包的限制(并且可以接收到设备端主动发送的通知)

2.手机端分包发送数据给设备端。

				int size = 168;
				byte[] bytes = s.getBytes();
                byte[] value = {0x4a, 0x58, 0x57, 0x40, 0x41, (byte) (bytes.length & 0xff)};
                byte[] concat = concat(value, bytes);
                List<byte[]> wifiInfos = new ArrayList<>();
                if (concat.length > size) {
                    for (int i = 0; i < concat.length; i += size) {
                        if (i + size < concat.length) {
                            byte[] infoData = new byte[size];
                            System.arraycopy(concat, i, infoData, 0, infoData.length);
                            wifiInfos.add(infoData);
                        } else {
                            byte[] infoData = new byte[concat.length - i];
                            System.arraycopy(concat, i, infoData, 0, infoData.length);
                            wifiInfos.add(infoData);
                        }
                    }
                } else {
                    wifiInfos.add(concat);
                }
                for (int i = 0; i < wifiInfos.size(); i++) {
                    byte[] concat1 = wifiInfos.get(i);
                    integrationData(concat1);
                    BluetoothHelper.getInstance(context).writeData(concat1, UUID_write);
                    try {
                        Thread.sleep(8);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

这样就完成了每次发送168个字节数据给设备端的操作

/*=============================================== 作者:LXZ-2008 FROM:CUMT 计08级 时间:2012-04-22 功能:能在SDK、MFC编程中实现笛卡尔 坐标系统的绘制,以及曲线,点的绘制。 特性:1.本程序采用面向对象思想设计; 2.具备很好的独立性,随时可以把这两个文件应 用在任意SDK、MFC开发中; 3.有良好的灵活性,扩展性,易用性,在稍微扩 展一下可以绘制任意曲线,图形; 4.具备良好的组合性,符合模块内高内聚,模块 外低耦合的思路; 5.整个程序仅有1300行左右代码,如果嫌代码过 多,可以把原先变量的PROTECTED保护类型打开, 换成PUBLIC,这样去掉GET和SET函数,这个思路 起源于我对J2EE中STRUTS2框架的学习以及对COM 组件技术的了解,它们也是这种思路这时可以省 下几百行代码。 6.当然也会有设计模式的思路在里面。 个人说明: 本程序花了我将近2天的时间编写,尽管开始有点 不想,但是还是觉得有意义,能给广大网友提供益处。 本系统的雏形来自2010年下半年的程序,当时花了 10天时间,弄了3千行代码。在现在看来当时的程序的 执行效率未必比现在的低,但是可维护性糟糕,可拓展 性糟糕,不具备良好的灵活性。需求改变了,代码会大 幅改变。换句话说,现在看来当时的程序是十分糟糕的, 生命周期已经结束。 而在用了面向对象的思想和设计模式,以及一些数 据结构去重新搭建这个系统的时候,代码其实1千多行就 搞定了,时间3-4天,不需要那么多(现在我来弄的话)。 主要起源于自己参与真实的有数十万代码的项目的开发, 这样提高了对程序开发的认识,以及商业程序应该如何 开发。同时也是自己面向对象思想和设计模式学习,对 自身思想的提高。 希望阅读代码的人觉得这些代码是优雅的,这就满 足了,尽管注释少了些,你们自己加吧。 QQ:706625262 E-MAIL:706625262@qq.com 不做商业和技术支持。 声明: 本程序代码未经本人同意,或者未给我MONEY的前提下, 不得用于商业目的,别让我鄙视你。在非商业目的使用 下请注明本人是原创,表学腾讯。 ==================================================*/
<think>好的,我现在需要回答用户关于Cesium中3D笛卡尔坐标系的使用和概念的问题。首先,我得回忆一下Cesium的基本知识,尤其是坐标系相关的部分。Cesium作为一款地理空间可视化库,坐标系的理解确实很重要。 用户提到了3D笛卡尔坐标系,我应该先解释这个概念。Cesium中使用的是右手坐标系,这可能和常见的其他坐标系有所不同,比如WebGL使用的是右手系,而有些其他库可能用左手系,这点需要明确。笛卡尔坐标通常表示为$(x, y, z)$,但在Cesium中,可能需要考虑不同的坐标系之间的转换,比如WGS84经纬度和笛卡尔坐标之间的转换。 接下来,用户可能想知道具体的用法,比如如何创建笛卡尔坐标点。这时候需要提到Cesium的API,比如Cartesian3类,以及如何通过fromDegrees方法将经纬度转换为三维坐标。例如,Cartesian3.fromDegrees(longitude, latitude, height)这样的方法,应该给出示例代码,但根据用户提供的示例,代码部分需要用代码块包裹,并注意语法正确。 另外,坐标转换也是重要的一部分。用户可能需要知道如何将笛卡尔坐标转换回经纬度高度,这时候可以使用Cartographic.fromCartesian方法。同时,需要注意椭球模型,比如默认的WGS84椭球,或者其他椭球的使用情况。 应用场景方面,比如在可视化、路径计算、地形分析中的使用。例如,计算两个点之间的距离,或者处理3D模型的位置。这部分需要结合实际的例子,说明笛卡尔坐标系在Cesium中的实际应用。 还要注意引用用户提供的参考内容。虽然用户的问题是关于笛卡尔坐标系的,但引用的内容提到了3DTileset和遮挡分析,可能在涉及几何计算或遮挡时,笛卡尔坐标系的应用会更明显。例如,3D Tiles Mask约束可能依赖于笛卡尔坐标来进行视线分析,这时候坐标系的精确性很重要。需要将引用内容自然地融入到回答中,比如在讲应用场景时提到遮挡分析时引用[^1]。 可能还需要提到坐标系之间的性能考虑,比如在大量数据计算时使用笛卡尔坐标的效率,或者与其他系统集成时的转换注意事项。例如,Cesium ion或GCS中的3D Tileset如何与笛卡尔坐标结合使用,这涉及到数据加载和空间分析时的坐标处理。 最后,生成相关问题,需要围绕笛卡尔坐标系展开,可能涉及转换方法、与其他坐标系的区别、性能优化、应用案例等。例如,如何转换坐标,右手坐标系的影响,性能优化方法,以及遮挡分析中的应用等。 现在需要确保回答结构清晰,分点讲解概念、核心用法、转换方法和应用场景。代码示例需要正确使用Cesium的API,比如Cartesian3的使用,并注意格式。引用部分在适当的位置加入,例如在遮挡分析时引用提供的参考内容。</think>### Cesium中3D笛卡尔坐标系的概念与用法 #### 1. 坐标系基础概念 Cesium的3D笛卡尔坐标系(Cartesian3)基于**右手坐标系**定义,三个轴分别对应: - **X轴**:指向赤道与本初子午线交点 - **Y轴**:指向赤道与东经90度交点 - **Z轴**:指向北极方向 所有坐标单位为**米**,原点为地球椭球体中心。该坐标系常用于**几何计算、空间分析和可视化定位**[^1]。 #### 2. 核心用法 **创建笛卡尔坐标**: ```javascript // 通过经纬度创建(经度, 纬度, 高度) const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 100); // 直接定义坐标 const point = new Cesium.Cartesian3(1e6, 2e6, 3e6); ``` **坐标转换**: ```javascript // 笛卡尔坐标 → 地理坐标(弧度) const cartographic = Cesium.Cartographic.fromCartesian(position); // 地理坐标 → 经纬度(角度) const longitude = Cesium.Math.toDegrees(cartographic.longitude); const latitude = Cesium.Math.toDegrees(cartographic.latitude); ``` #### 3. 关键API方法 | 方法 | 用途 | |------|------| | `Cartesian3.fromDegrees()` | 经纬度转笛卡尔坐标 | | `Cartographic.fromCartesian()` | 笛卡尔坐标转地理坐标 | | `Ellipsoid.WGS84.cartesianToCartographic()` | 指定椭球体转换 | #### 4. 应用场景 1. **几何计算** 计算两点距离: $$ distance = \| \vec{P_2} - \vec{P_1} \| $$ ```javascript const distance = Cesium.Cartesian3.distance(p1, p2); ``` 2. **3D可视化定位** 定位3D模型时需使用笛卡尔坐标: ```javascript viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.39, 39.9), model: { uri: "model.glb" } }); ``` 3. **空间分析** 在遮挡分析中,3DTiles Mask约束依赖笛卡尔坐标系判断视线遮挡关系(如建筑物遮挡卫星可见性)[^1]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值