nrf52811墨水屏edp_service.c文件学习

on_connect函数

/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.** @param[in] p_epd     EPD Service structure.* @param[in] p_ble_evt Pointer to the event received from BLE stack.*/
static void on_connect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
{p_epd->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;EPD_GPIO_Init();
}
函数功能概述

on_connect函数是蓝牙低功耗 (BLE) 事件处理的核心部分,主要在设备成功建立蓝牙连接时被触发。其核心功能是管理连接句柄并初始化电子纸显示屏 (EPD) 的 GPIO 引脚配置。

代码详细解析
/*** @brief 处理S110 SoftDevice的BLE_GAP_EVT_CONNECTED事件* @param[in] p_epd       EPD服务结构指针,包含连接状态和配置信息* @param[in] p_ble_evt   BLE事件指针,包含连接事件的具体数据*/
static void on_connect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
{// 1. 保存连接句柄p_epd->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;// 2. 初始化EPD相关的GPIO引脚EPD_GPIO_Init();
}
关键操作说明
  1. 连接句柄管理

    • 通过p_ble_evt->evt.gap_evt.conn_handle获取蓝牙连接的句柄(conn_handle
    • 将句柄存储到p_epd->conn_handle中,用于后续通信时标识该连接
    • 连接句柄是 BLE 通信的基础,类似网络连接中的 Socket 描述符
  2. GPIO 初始化

    • 调用EPD_GPIO_Init()函数初始化 EPD 硬件相关的 GPIO 引脚
    • 初始化操作可能包括:
      • 设置引脚方向(输入 / 输出)
      • 配置引脚电平(上拉 / 下拉)
      • 初始化 SPI/I2C 等通信接口的引脚
    • 这一步为后续 EPD 显示数据传输做好硬件准备
实际应用场景

当手机或其他 BLE 主机设备扫描并连接到搭载该代码的设备时:

  1. 蓝牙协议栈会生成BLE_GAP_EVT_CONNECTED事件
  2. 事件处理框架会调用on_connect函数
  3. 函数保存连接句柄并初始化 EPD 硬件,使设备准备好接收主机发送的显示指令
  4. 后续主机可通过该连接句柄向 EPD 发送数据(如时间、图像等)
潜在优化点
  1. 错误处理补充
    可添加EPD_GPIO_Init()的返回值检查,确保初始化成功:

    uint32_t err_code = EPD_GPIO_Init();
    if (err_code != NRF_SUCCESS) {NRF_LOG_ERROR("EPD GPIO init failed, error: %d", err_code);// 可选:断开连接或记录错误状态
    }
    
  2. 功耗优化
    若系统对功耗敏感,可在初始化时配置 GPIO 引脚的低功耗模式:

    void EPD_GPIO_Init() {// 示例:配置引脚为低功耗输出模式nrf_gpio_cfg_output(引脚号);nrf_gpio_pin_write(引脚号, 低电平);
    }
    
  3. 连接参数记录
    可扩展代码以记录连接参数(如连接间隔、超时时间):

    p_epd->conn_params.interval = p_ble_evt->evt.gap_evt.params.conn_params.interval;
    p_epd->conn_params.timeout = p_ble_evt->evt.gap_evt.params.conn_params.timeout;
    
与其他函数的协作关系
  • on_disconnect函数对应
    连接时调用EPD_GPIO_Init(),断开时调用EPD_GPIO_Uninit()释放资源
  • epd_service_on_write函数协作
    连接建立后,on_connect保存的conn_handle用于ble_epd_string_send等函数发送数据
  • 与硬件驱动的交互
    EPD_GPIO_Init()依赖底层 GPIO 驱动实现引脚配置

该函数是 BLE 连接建立后硬件初始化的关键环节,确保 EPD 设备在连接状态下能正常接收和处理显示指令。


ble_evt_t结构体解析

结构体概述

ble_evt_t是蓝牙低功耗 (BLE) 协议栈中用于表示各类事件的核心数据结构。它采用 "事件头 + 事件联合体" 的设计模式,能够高效处理不同类型的 BLE 事件,同时保持内存占用的最小化。

结构体定义详解
typedef struct
{ble_evt_hdr_t header;           /**< 事件头,包含事件类型标识等公共信息 */union{ble_common_evt_t  common_evt; /**< 通用事件,事件ID属于BLE_EVT_*系列 */ble_gap_evt_t     gap_evt;    /**< GAP层事件,事件ID属于BLE_GAP_EVT_*系列 */ble_gattc_evt_t   gattc_evt;  /**< GATT客户端事件,事件ID属于BLE_GATTC_EVT*系列 */ble_gatts_evt_t   gatts_evt;  /**< GATT服务器事件,事件ID属于BLE_GATTS_EVT*系列 */} evt;                          /**< 事件联合体,根据事件类型存储具体事件数据 */
} ble_evt_t;
核心成员解析
1. header字段 - 事件头结构
  • 类型ble_evt_hdr_t(通常包含事件 ID 和长度信息)
  • 作用
    • 标识事件类型(通过header.evt_id
    • 提供事件数据长度(通过header.evt_len
    • 作为所有事件的公共前缀,便于统一处理
typedef struct
{uint16_t evt_id;                /**< Value from a BLE_<module>_EVT series. */uint16_t evt_len;               /**< Length in octets including this header. */
} ble_evt_hdr_t;

 

2. evt联合体 - 事件具体数据

联合体设计的核心优势是内存共享,不同事件类型复用同一块内存空间:

联合体成员对应事件类型典型应用场景
common_evt通用基础事件协议栈内部状态变化
gap_evtGAP(通用访问配置文件)事件连接建立、断开、设备发现等
gattc_evtGATT 客户端事件读取 / 写入远程服务数据
gatts_evtGATT 服务器事件接收客户端写入、通知请求等
设计模式分析

这种 "头部 + 联合体" 的设计属于标记联合模式 (Tagged Union),在嵌入式系统中非常常见:

  1. 空间效率

    • 无论处理哪种事件,结构体总大小等于header + 最大事件结构体的大小
    • 避免为每种事件类型单独分配内存
  2. 类型安全

    • 通过header.evt_id判断当前事件类型
    • 确保访问联合体成员时类型匹配
  3. 扩展性

    • 新增事件类型时只需扩展联合体成员
    • 保持结构体接口兼容性
典型使用场景

在事件处理函数中,通常按以下流程处理ble_evt_t

void ble_evt_handler(ble_evt_t *p_ble_evt)
{// 1. 通过事件头获取事件类型uint32_t evt_id = p_ble_evt->header.evt_id;// 2. 根据事件类型处理不同事件switch (evt_id){case BLE_GAP_EVT_CONNECTED:// 处理连接事件,使用p_ble_evt->evt.gap_evton_connect(p_epd, p_ble_evt);break;case BLE_GATTS_EVT_WRITE:// 处理写入事件,使用p_ble_evt->evt.gatts_evton_write(p_epd, p_ble_evt);break;// 其他事件处理...default:break;}
}
内存布局与对齐注意事项
  1. 内存对齐

    • 联合体成员需遵循最大对齐规则
    • 例如:若ble_gatts_evt_t包含 64 位成员,则整个联合体按 8 字节对齐
  2. 内存占用计算

    sizeof(ble_evt_t) = sizeof(ble_evt_hdr_t) + max(sizeof(ble_common_evt_t),sizeof(ble_gap_evt_t),sizeof(ble_gattc_evt_t),sizeof(ble_gatts_evt_t)
    )
    
  3. 跨平台注意事项

    • 需通过#pragma pack等指令控制结构体对齐
    • 避免因不同编译器对齐规则导致的协议兼容性问题
与其他结构的关联
  • ble_evt_hdr_t结构
    通常包含uint16_t evt_iduint16_t evt_len字段,作为所有事件的公共标识

  • 各事件具体结构

    • ble_gap_evt_t包含连接句柄、连接参数等 GAP 层数据
    • ble_gatts_evt_t包含服务句柄、特征值句柄等 GATT 服务器数据
    • 这些结构根据蓝牙核心规范定义,确保协议兼容性

这种设计使得 BLE 协议栈能够以统一接口处理各类事件,同时保持高效的内存使用,非常适合资源受限的嵌入式系统环境。


ble_gap_evt_t结构体深度解析

结构体整体架构

ble_gap_evt_t是蓝牙低功耗 (GAP) 层事件的核心数据结构,用于表示设备在连接、断开、安全认证等过程中产生的各类事件。其设计采用 "连接句柄 + 事件参数联合体" 的模式,能够高效处理多种 GAP 事件类型。

typedef struct
{uint16_t conn_handle;                                     /**< 事件发生的连接句柄 */union                                                     /**< 事件参数联合体,由外层结构体的evt_id标识当前类型 */{ble_gap_evt_connected_t                   connected;                    /**< 连接事件参数 */ble_gap_evt_disconnected_t                disconnected;                 /**< 断开连接事件参数 */ble_gap_evt_conn_param_update_t           conn_param_update;            /**< 连接参数更新事件参数 */// 省略中间事件类型...ble_gap_evt_phy_update_request_t          phy_update_request;           /**< PHY更新请求事件参数 */ble_gap_evt_phy_update_t                  phy_update;                   /**< PHY更新事件参数 */} params;                                                                 /**< 事件具体参数 */
} ble_gap_evt_t;
核心成员详解
1. conn_handle - 连接句柄
  • 类型uint16_t
  • 作用
    • 唯一标识一个蓝牙连接,类似网络通信中的 Socket 句柄
    • 在多连接场景中用于区分不同的客户端连接
    • 所有 GAP 事件都与特定连接相关联
2. params联合体 - 事件参数集合

联合体包含 16 种不同类型的事件参数结构,以下是关键事件类型解析:

事件类型事件 ID 前缀核心应用场景
connectedBLE_GAP_EVT_CONNECTED蓝牙连接建立时,携带连接参数和句柄
disconnectedBLE_GAP_EVT_DISCONNECTED连接断开时,携带断开原因码
conn_param_updateBLE_GAP_EVT_CONN_PARAM_UPDATE连接参数(间隔、超时等)更新时
sec_params_requestBLE_GAP_EVT_SEC_PARAMS_REQUEST安全参数请求,如加密密钥协商
auth_statusBLE_GAP_EVT_AUTH_STATUS认证状态通知,携带认证结果
timeoutBLE_GAP_EVT_TIMEOUT连接或操作超时,携带超时类型
rssi_changedBLE_GAP_EVT_RSSI_CHANGED接收信号强度变化,携带 RSSI 值
设计模式与内存优化

这种 "句柄 + 联合体" 的设计体现了嵌入式系统中典型的空间效率优先原则

  1. 内存共享机制

    • 无论处理哪种事件,联合体仅占用最大事件结构的内存空间
    • 例如:ble_gap_evt_connected_t通常比ble_gap_evt_timeout_t更复杂,联合体大小由前者决定
  2. 类型安全控制

    • 通过外层ble_evt_theader.evt_id字段判断当前事件类型
    • 确保访问联合体成员时类型匹配,避免内存越界
  3. 协议兼容性设计

    • 结构体定义严格遵循蓝牙核心规范 v5.3
    • 新增事件类型时只需扩展联合体成员,不破坏现有接口
典型事件处理流程

以下是处理BLE_GAP_EVT_CONNECTED事件的示例代码,展示如何解析ble_gap_evt_t

c

void ble_evt_handler(ble_evt_t *p_ble_evt)
{if (p_ble_evt->header.evt_id == BLE_GAP_EVT_CONNECTED){// 1. 获取连接句柄uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;// 2. 解析连接事件参数ble_gap_evt_connected_t *p_connected = &p_ble_evt->evt.gap_evt.params.connected;// 3. 提取连接参数uint16_t conn_interval = p_connected->conn_params.interval;    // 连接间隔 (1.25ms单位)uint16_t conn_latency  = p_connected->conn_params.latency;     // 连接延迟uint16_t supervision_timeout = p_connected->conn_params.sup_timeout; // 超时时间// 4. 业务逻辑处理on_connect(p_epd, p_ble_evt);}
}

内存布局与对齐考量
  1. 对齐规则

    • 联合体成员按各自结构的最大对齐要求进行内存对齐
    • 例如:若ble_gap_evt_connected_t包含 32 位成员,则整个联合体按 4 字节对齐
  2. 内存占用计算

    plaintext

    sizeof(ble_gap_evt_t) = sizeof(uint16_t) + max(sizeof(ble_gap_evt_connected_t),sizeof(ble_gap_evt_disconnected_t),// ... 其他事件结构大小sizeof(ble_gap_evt_phy_update_t)
    )
    

  3. 编译器优化建议

    • 使用#pragma pack(push, 4)等指令控制对齐,避免字节填充浪费内存
    • 在跨平台开发中,通过__attribute__((packed))确保结构体布局一致
与其他结构的协作关系
  1. ble_evt_t的关系

    • ble_gap_evt_tble_evt_t联合体中的一个成员
    • 通过ble_evt_t->evt.gap_evt访问 GAP 事件相关数据
  2. 与事件处理函数的交互

    • on_connecton_disconnect等函数接收ble_evt_t*指针
    • 通过类型转换获取ble_gap_evt_t中的具体事件参数
  3. 与协议栈的集成

    • 结构体定义由 Nordic Semiconductor SDK 提供
    • 底层协议栈填充事件数据后,通过回调函数传递给应用层

这种设计使得应用层能够以统一接口处理各类 GAP 事件,同时保持对底层硬件资源的高效利用,非常适合低功耗蓝牙设备的开发场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/85004.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx-2 详解处理 Http 请求

Nginx-2 详解处理 Http 请求 Nginx 作为当今最流行的开源 Web 服务器之一&#xff0c;以其高性能、高稳定性和丰富的功能而闻名。在处理 HTTP请求 的过程中&#xff0c;Nginx 采用了模块化的设计&#xff0c;将整个请求处理流程划分为若干个阶段&#xff0c;每个阶段都可以由特…

40-Oracle 23 ai Bigfile~Smallfile-Basicfile~Securefile矩阵对比

小伙伴们是不是在文件选择上还默认给建文件4G/个么&#xff0c;在oracle每个版本上系统默认属性是什么&#xff0c;选择困难症了没&#xff0c;一起一次性文件存储和默认属性看透。 基于Oracle历代在存储架构的技术演进分析&#xff0c;结合版本升级和23ai新特性&#xff0c;一…

【一】零基础--分层强化学习概览

分层强化学习&#xff08;Hierarchical Reinforcement Learning, HRL&#xff09;最早一般视为1993 年封建强化学习的提出. 一、HL的基础理论 1.1 MDP MDP&#xff08;马尔可夫决策过程&#xff09;&#xff1a;MDP是一种用于建模序列决策问题的框架&#xff0c;包含状态&am…

Java延时

在 Java 中实现延时操作主要有以下几种方式&#xff0c;根据使用场景选择合适的方法&#xff1a; 1. Thread.sleep()&#xff08;最常用&#xff09; java 复制 下载 try {// 延时 1000 毫秒&#xff08;1秒&#xff09;Thread.sleep(1000); } catch (InterruptedExcepti…

电阻篇---下拉电阻的取值

下拉电阻的取值需要综合考虑电路驱动能力、功耗、信号完整性、噪声容限等多方面因素。以下是详细的取值分析及方法&#xff1a; 一、下拉电阻的核心影响因素 1. 驱动能力与电流限制 单片机 IO 口驱动能力&#xff1a;如 STM32 的 IO 口在输入模式下的漏电流通常很小&#xf…

NY271NY274美光科技固态NY278NY284

美光科技NY系列固态硬盘深度剖析&#xff1a;技术、市场与未来 技术前沿&#xff1a;232层NAND架构与性能突破 在存储技术的赛道上&#xff0c;美光科技&#xff08;Micron&#xff09;始终是行业领跑者。其NY系列固态硬盘&#xff08;SSD&#xff09;凭借232层NAND闪存架构的…

微信开发者工具 插件未授权使用,user uni can not visit app

参考&#xff1a;https://www.jingpinma.cn/archives/159.html 问题描述 我下载了一个别人的小程序&#xff0c;想运行看看效果&#xff0c;结果报错信息如下 原因 其实就是插件没有安装&#xff0c;需要到小程序平台安装插件。处理办法如下 在 app.json 里&#xff0c;声…

UE5 读取配置文件

使用免费的Varest插件&#xff0c;可以读取本地的json数据 获取配置文件路径&#xff1a;当前配置文件在工程根目录&#xff0c;打包后在 Windows/项目名称 下 读取json 打包后需要手动复制配置文件到Windows/项目名称 下

【kdump专栏】KEXEC机制中SME(安全内存加密)

【kdump专栏】KEXEC机制中SME&#xff08;安全内存加密&#xff09; 原始代码&#xff1a; /* Ensure that these pages are decrypted if SME is enabled. */ 533 if (pages) 534 arch_kexec_post_alloc_pages(page_address(pages), 1 << order, 0);&#x1f4cc…

C# vs2022 找不到指定的 SDK“Microsof.NET.Sdk

找不到指定的 SDK"Microsof.NET.Sdk 第一查 看 系统盘目录 C:\Program Files\dotnet第二 命令行输入 dotnet --version第三 检查环境变量总结 只要执行dotnet --version 正常返回版本号此问题即解决 第一查 看 系统盘目录 C:\Program Files\dotnet 有2种方式 去检查 是否…

Pytest断言全解析:掌握测试验证的核心艺术

Pytest断言全解析&#xff1a;掌握测试验证的核心艺术 一、断言的本质与重要性 什么是断言&#xff1f; 断言是自动化测试中的验证检查点&#xff0c;用于确认代码行为是否符合预期。在Pytest中&#xff0c;断言直接使用Python原生assert语句&#xff0c;当条件不满足时抛出…

【编译原理】题目合集(一)

未经许可,禁止转载。 文章目录 选择填空综合选择 将编译程序分成若干个“遍”是为了 (D.利用有限的机器内存,但降低了执行效率) A.提高程序的执行效率 B.使程序的结构更加清晰 C.利用有限的机器内存并提高执行效率 D.利用有限的机器内存,但降低了执行效率 词法分析…

uni-app项目实战笔记13--全屏页面的absolute定位布局和fit-content自适应内容宽度

本篇主要实现全屏页面的布局&#xff0c;其中还涉及内容自适应宽度。 创建一个preview.vue页面用于图片预览&#xff0c;写入以下代码&#xff1a; <template><view class"preview"><swiper circular><swiper-item v-for"item in 5&quo…

OVS Faucet Tutorial笔记(下)

官方文档&#xff1a; OVS Faucet Tutorial 5、Routing Faucet Router 通过控制器模拟三层网关&#xff0c;提供 ARP 应答、路由转发功能。 5.1 控制器配置 5.1.1 编辑控制器yaml文件&#xff0c;增加router配置 rootserver1:~/faucet/inst# vi faucet.yaml dps:switch-1:d…

PCB设计教程【大师篇】stm32开发板PCB布线(信号部分)

前言 本教程基于B站Expert电子实验室的PCB设计教学的整理&#xff0c;为个人学习记录&#xff0c;旨在帮助PCB设计新手入门。所有内容仅作学习交流使用&#xff0c;无任何商业目的。若涉及侵权&#xff0c;请随时联系&#xff0c;将会立即处理 1. 布线优先级与原则 - 遵循“重…

Phthon3 学习记录-0613

List&#xff08;列表&#xff09;、Tuple&#xff08;元组&#xff09;、Set&#xff08;集合&#xff09;和 Dictionary&#xff08;字典&#xff09; 在接口自动化测试中&#xff0c;List&#xff08;列表&#xff09;、Tuple&#xff08;元组&#xff09;、Set&#xff08…

UVa12298 3KP-BASH Project

UVa12298 3KP-BASH Project 题目链接题意输入格式输出格式 分析AC 代码 题目链接 UVa12298 3KP-BASH Project 题意 摘自 《算法竞赛入门经典&#xff1a;训练指南》刘汝佳&#xff0c;陈锋著。有删改。 你的任务是为一个假想的 3KP 操作系统编写一个简单的 Bash 模拟器。由于操…

云打包生成的ipa上传构建版本经验分享

在上架ios应用&#xff0c;在苹果开发者中心操作的时候&#xff0c;需要提供一个构建版本&#xff0c;如下图所示&#xff1a; 点击蓝色加号&#xff0c;添加构建版本&#xff0c;但是点击蓝色加号后&#xff0c;并没有构建版本可以选。 原因是需要下载下面它推荐的工具来上传…

ESP32的spi通讯(Arduino)

目录 一.基本配置 1.esp32-wroom-32引脚图 2.接线方式 3.Arduino芯片选择和库文件 3.1Arduino配置&#xff08;2.0.11&#xff09; 3.2 下载ESP32SPISlave库&#xff08;0.6.8&#xff09;文件 二、代码编写 1.主机代码 2.从机代码 3.注意事项 三、运行效果 一.基本…

Spring-rabbit重试消费源码分析

在集成RabbitMQ与Spring Boot 3.1.x时&#xff0c;RetryOperationsInterceptor 是实现消息重试机制的关键组件。这里将深入分析 RetryOperationsInterceptor 的工作原理&#xff0c;尤其是在消费者消费失败时的行为&#xff0c;并结合底层源码进行详解。 一、配置解析 首先&a…