蓝牙墨水屏上位机学习(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 功能至关重要。


相关推荐
西岸行者10 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意10 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码10 天前
嵌入式学习路线
学习
毛小茛10 天前
计算机系统概论——校验码
学习
babe小鑫10 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms10 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下10 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。10 天前
2026.2.25监控学习
学习
im_AMBER10 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J10 天前
从“Hello World“ 开始 C++
c语言·c++·学习