蓝牙墨水屏上位机学习(2)

界面如下 :

第一节,蓝牙连接按键学习

html 复制代码
<body>
    <div class="main">
        <h3>电子墨水屏蓝牙控制器</h3>
        <fieldset>
            <legend>蓝牙连接</legend>
            <div class="flex-container">
                <div class="flex-group">
                    <button id="connectbutton" type="button" class="primary" onclick="preConnect()">连接</button>
                    <button id="reconnectbutton" type="button" class="secondary" onclick="reConnect()">重连</button>
					<button type="button" class="secondary" onclick="clearLog()">清空日志</button>
                </div>

preConnect()函数定义如下 :该函数定义在main.js中

javascript 复制代码
async function preConnect() {
  if (gattServer != null && gattServer.connected) {
    if (bleDevice != null && bleDevice.gatt.connected) {
      bleDevice.gatt.disconnect();
    }
  }
  else {
    resetVariables();
    try {
      bleDevice = await navigator.bluetooth.requestDevice({
        optionalServices: ['62750001-d828-918d-fb46-b6c11c675aec'],
        acceptAllDevices: true
      });
    } catch (e) {
      console.error(e);
      if (e.message) addLog("requestDevice: " + e.message);
      addLog("请检查蓝牙是否已开启,且使用的浏览器支持蓝牙!建议使用以下浏览器:");
      addLog("• 电脑: Chrome/Edge");
      addLog("• Android: Chrome/Edge");
      addLog("• iOS: Bluefy 浏览器");
      return;
    }

    await bleDevice.addEventListener('gattserverdisconnected', disconnect);
    setTimeout(async function () { await connect(); }, 300);
  }
}

这段代码是一个使用 Web Bluetooth API 的异步函数,用于处理蓝牙设备的预连接流程。下面我将逐行解释其功能和逻辑:

复制代码
async function preConnect() {
  // 检查当前是否已有连接的 GATT 服务器
  if (gattServer != null && gattServer.connected) {
    // 检查 BLE 设备是否已连接
    if (bleDevice != null && bleDevice.gatt.connected) {
      // 如果已连接,则断开当前连接
      bleDevice.gatt.disconnect();
    }
  }
  else {
    // 如果没有活动连接,则重置相关变量
    resetVariables();
    
    try {
      // 请求用户选择蓝牙设备
      bleDevice = await navigator.bluetooth.requestDevice({
        // 指定需要访问的服务 UUID(这里是一个自定义服务)
        optionalServices: ['62750001-d828-918d-fb46-b6c11c675aec'],
        // 允许选择所有设备(无论是否包含指定服务)
        acceptAllDevices: true
      });
    } catch (e) {
      // 处理设备选择过程中的错误
      console.error(e);
      if (e.message) addLog("requestDevice: " + e.message);
      
      // 提示用户检查蓝牙和浏览器兼容性
      addLog("请检查蓝牙是否已开启,且使用的浏览器支持蓝牙!建议使用以下浏览器:");
      addLog("• 电脑: Chrome/Edge");
      addLog("• Android: Chrome/Edge");
      addLog("• iOS: Bluefy 浏览器");
      return; // 发生错误时退出函数
    }

    // 添加事件监听器,当 GATT 服务器断开连接时调用 disconnect() 函数
    await bleDevice.addEventListener('gattserverdisconnected', disconnect);
    
    // 延迟 300ms 后调用 connect() 函数建立实际连接
    setTimeout(async function () { await connect(); }, 300);
  }
}

核心功能与设计逻辑

  1. 连接管理

    • 函数首先检查是否存在已连接的 GATT 服务器,如果是则断开当前连接
    • 这种设计确保在建立新连接前清理旧连接,避免资源冲突
  2. 设备选择流程

    • 使用 navigator.bluetooth.requestDevice() 触发浏览器的设备选择对话框
    • optionalServices 参数指定需要访问的蓝牙服务 UUID(用于 OTA 升级的服务)
    • acceptAllDevices: true 允许用户选择任何蓝牙设备,无论是否包含指定服务
  3. 错误处理机制

    • 捕获设备选择过程中的异常(如用户取消选择、蓝牙未开启等)
    • 提供详细的错误提示,包括浏览器兼容性建议(Web Bluetooth 在不同浏览器支持差异较大)
  4. 事件监听与异步连接

    • 添加 gattserverdisconnected 事件监听器,确保设备断开时能及时响应
    • 使用 setTimeout 延迟调用 connect() 函数,为设备准备提供缓冲时间

与 OTA 升级的关联

此函数是蓝牙 OTA 升级流程的前期准备阶段,主要完成:

  • 设备发现与选择
  • 基础连接建立
  • 连接状态管理

后续的 OTA 数据传输通常会在 connect() 函数中实现,包括:

  • 连接到指定服务和特征
  • 发送固件数据
  • 接收设备状态反馈
  • 验证升级结果

潜在优化建议

  1. 增加连接超时处理

    复制代码
    // 在 setTimeout 中添加超时逻辑
    const connectTimeout = setTimeout(() => {
      addLog("连接超时,请重试");
    }, 5000); // 5秒超时
    
    await connect();
    clearTimeout(connectTimeout); // 连接成功后清除超时
  2. 优化错误提示信息

    • 根据不同错误类型提供更具体的解决方案
    • 例如区分 "用户取消" 和 "蓝牙未开启" 等不同错误场景
  3. 增强连接稳定性

    • 添加重连机制(如自动重试 2-3 次)
    • 实现连接状态监控(定期检查连接状态)

这个预连接函数为后续的 OTA 升级操作奠定了基础,确保设备连接的可靠性和稳定性。


GATT 服务器是什么?蓝牙通信的核心概念解析

一、GATT 基础定义

GATT(Generic Attribute Profile) 是蓝牙低功耗(BLE)技术中的核心通信协议,定义了设备间如何组织和交换数据。GATT 服务器是该协议中的核心角色,负责:

  • 存储数据(以特征服务的形式组织)
  • 响应客户端的数据请求
  • 主动向客户端发送数据更新
二、GATT 服务器的核心组件

GATT 服务器的结构采用分层模型,从抽象到具体依次为:

  1. 服务(Service)

    • 服务是相关功能的集合,例如 "电池信息服务"、"心率监测服务" 或 "OTA 升级服务"。
    • 每个服务有唯一的 UUID(Universally Unique Identifier),例如:
      • 电池服务 UUID:0x180F(标准服务)
      • OTA 服务 UUID:62750001-d828-918d-fb46-b6c11c675aec(自定义服务)
  2. 特征(Characteristic)

    • 特征是服务中的具体数据项,例如 "电池电量百分比"、"心率值"。
    • 每个特征包含:
      • 值(Value):实际数据(如电池电量 85%)。
      • 属性(Properties):定义如何访问该特征(如可读、可写、可通知)。
      • 描述符(Descriptor):提供关于特征的额外元数据(如单位、范围)。
  3. 描述符(Descriptor)

    • 描述符是特征的元数据,例如 "测量单位"、"数据格式"。
    • 示例:心率特征的描述符可能标明 "单位:次 / 分钟"。
三、GATT 客户端与服务器的交互模式

在蓝牙通信中,客户端(Client)服务器(Server) 角色通常由设备功能决定:

  • 服务器 :通常是被连接的设备(如智能手表、耳机),持有数据。
  • 客户端 :通常是发起连接的设备(如手机、电脑),请求或接收数据。

典型交互流程

  1. 连接建立:客户端通过 BLE 物理链路连接到服务器。
  2. 服务发现:客户端请求服务器列出所有可用服务和特征。
  3. 数据交换 :客户端通过以下方式与服务器交互:
    • 读取(Read):获取特征的当前值(如读取电池电量)。
    • 写入(Write):修改特征的值(如设置设备名称)。
    • 通知 / 指示(Notify/Indicate):服务器主动向客户端发送数据更新(如心率变化)。
四、在 OTA 升级中的应用

在蓝牙 OTA 升级场景中,GATT 服务器的角色尤为关键:

  1. OTA 服务设计

    • 设备(如耳机)作为 GATT 服务器,暴露一个自定义 OTA 服务
    • 该服务包含多个特征,例如:
      • 固件接收特征:客户端(手机)写入固件数据。
      • 状态反馈特征:服务器发送升级进度(如 "已接收 50%")。
      • 控制命令特征:用于启动 / 暂停 / 确认升级。
  2. 数据传输流程

    • 客户端将固件包拆分为小片段(通常 ≤256 字节)。
    • 客户端通过写入请求将片段发送到服务器的固件接收特征。
    • 服务器接收数据,验证完整性,并通过状态反馈特征返回进度。
  3. 安全机制

    • GATT 层支持加密和认证,确保固件传输过程不被篡改。
    • 服务器可能要求客户端提供认证密钥或数字签名。
五、GATT 服务器的实现示例

以下是一个简化的伪代码示例,展示如何在设备端实现一个 OTA 服务的 GATT 服务器:

复制代码
// 伪代码:设备端实现 OTA 服务的 GATT 服务器
async function setupOTAService() {
  // 创建 GATT 服务器
  const server = await navigator.bluetooth.requestLEScan();
  
  // 创建 OTA 服务
  const otaService = await server.getPrimaryService('62750001-d828-918d-fb46-b6c11c675aec');
  
  // 创建固件接收特征(可写)
  const firmwareCharacteristic = await otaService.createCharacteristic(
    '62750002-d828-918d-fb46-b6c11c675aec',
    { properties: { write: true } }
  );
  
  // 创建状态反馈特征(可通知)
  const statusCharacteristic = await otaService.createCharacteristic(
    '62750003-d828-918d-fb46-b6c11c675aec',
    { properties: { notify: true } }
  );
  
  // 监听固件数据写入
  firmwareCharacteristic.addEventListener('characteristicvaluechanged', (event) => {
    const firmwareData = event.target.value;
    // 处理接收到的固件数据片段
    processFirmwareChunk(firmwareData);
    
    // 更新并发送升级进度
    const progress = calculateProgress();
    statusCharacteristic.setValue(progress);
  });
  
  return server;
}
六、总结

GATT 服务器是蓝牙设备通信的核心组件,通过服务、特征和描述符的层次结构组织数据。在 OTA 升级中,GATT 服务器负责接收固件数据、执行升级过程并反馈状态,确保整个过程的可靠性和安全性。理解 GATT 服务器的工作原理对于开发蓝牙应用和实现 OTA 功能至关重要。


相关推荐
Chef_Chen40 分钟前
从0开始学习计算机视觉--Day08--卷积神经网络
学习·计算机视觉·cnn
weixin_4462608540 分钟前
Isaac Lab:让机器人学习更简单的开源框架
学习·机器人
我真不会起名字啊2 小时前
OpenSceneGraph(OSG)开发学习
学习
永日456702 小时前
学习日记-spring-day42-7.7
java·学习·spring
Love__Tay6 小时前
笔记/云计算基础
笔记·学习·云计算
wuxuanok9 小时前
Web后端开发-分层解耦
java·笔记·后端·学习
wuxuanok9 小时前
Web后端开发-请求响应
java·开发语言·笔记·学习
i7i8i9com9 小时前
后端微服务基础架构Spring Cloud
学习
蜡笔小电芯10 小时前
【C语言】指针与回调机制学习笔记
c语言·笔记·学习
im_AMBER11 小时前
学习日志03 python
学习