实习笔记(五)面板 board 按钮状态解析任务

一、任务概述

新增功能:读取主控面板 board 按钮的 BSP 节点,解析按钮是否按下(0/1),并以可读文本打印到日志。

  • BSP 节点:/sys/class/misc‑board//handle_button
  • 含义:0 = 未按下(released)1 = 按下(pressed)
  • 要求:只做解析 + 打印日志(暂不做事件外发)

二、任务分析

1. 仿照已有代码,降低风险

项目里已有类似 "读 BSP 节点‑解析" 的成熟示例(如update_backlight_running_hour读取背光运行时间),仿照其模式,保证代码风格一致、符合项目编码规范。

2. 调用入口(秒级定时)

这个功能需要周期性读取,而update_system_service_info()是每秒被定时调用的函数,专门负责采集各类系统状态。

  • 新增一个函数:update_board_button_status()
  • update_system_service_info()里面调用该函数

3. 理解事件外发机制

虽然这次只做打印,但需要理解完整事件收发链路:

后端读到值 → 构造 CoreEvent (type+id+payload) → dispatch_event 发出 → CoreEventHub 按 type 自动路由 → 前端 (ClientProxy) 监听对应 id → 前端拿取数据

  • type:事件发给哪类组件,例如EV_TYPE_LOCAL_CLIENT_PROXY发往前端
  • id:具体什么事件(枚举,例EV_MCP_UPDATE_BACKLIGHT_RUNNING_HOUR
  • payload:携带的数据,std::any,可以存放任意类型数据
  • 监听、业务处理逻辑,全部由接收方(前端)负责;发送方只管把事件发出去。

边界:后端只管dispatch_event发出去,后端路由不用管;前端能不能真正拿到,取决于前端是否监听这个 id。如果是全新事件,前端还需要配合增加监听。

4. 新事件需要做两步

如果后续要做事件外发新事件:

  1. eventdefine.hCoreEventID枚举里新增 id
  2. 前端配合监听该 id

本次任务只做日志打印,不需要上面两步。

三、代码实现

1. 定义路径常量(规范:不裸写字符串)

仿照背光的BACKLIGHT_BSP_FILE_PATH,把路径抽成常量,不直接裸写字符串,方便后续统一维护。

复制代码
// 面板按钮BSP文件路径
static const char* const BOARD_BUTTON_BSP_FILE_PATH =
"/sys/class/misc‑board/arcadia/handle_button";

2. 实现函数(核心逻辑)

复制代码
/**
 * @fn void update_board_button_status()
 * @brief 面板按钮状态
 * @details 读取BSP节点,0=未按下(released),1=按下(pressed)
 */
void SystemManager::update_board_button_status() {
    int button_state = -1;                    // 初始‑1作为"无效值"兜底
    std::ifstream file(BOARD_BUTTON_BSP_FILE_PATH); // 打开BSP节点文件
    if (!file.is_open()) {                    // 打开失败
        SYSMGR_WARN("open file :{} failed!", BOARD_BUTTON_BSP_FILE_PATH);
        return;
    }

    file >> button_state;                     // 从文件读取按钮值
    if (file.fail()) {                        // 读取出错(非数字)
        SYSMGR_INFO("{} read board button status failed, not number!",
                BOARD_BUTTON_BSP_FILE_PATH);
        file.close();
        return;
    }
    file.close();                             // 关闭文件

    if (button_state == -1) {                 // 值无效
        return;
    }

    // 0/1 转可读文本
    const char* button_state_str =
        (button_state == 0) ? "released" : "pressed";
    SYSMGR_INFO("board button status:{}", button_state_str); // 打印日志
}

3. 头文件 (.h) 声明 + cpp (.cpp) 调用

.h 头文件声明

复制代码
void update_board_button_status();

.cpp 调用(放在 update_system_service_info 里面)

复制代码
void SystemManager::update_system_service_info() {
    ...
    update_backlight_running_hour();
    update_board_button_status();   // 新增,每秒调用一次
    ...
}

四、关键知识点

1. 读取 BSP(内核驱动节点)

应用层不需要关心驱动底层实现,但必须清楚文件路径与文件内数据格式。

  • file >> value; 从 sysfs 文件读取一个数值
  • file.is_open() 判断文件是否打开成功
  • file.fail() 判断读取操作是否失败

2. 命名规范

  • 函数名、路径常量名语义保持一致;本次全部使用board,和 BSP 节点handle_button/misc‑board对应,避免命名前后矛盾。
  • 常量名具备可读性:BOARD_BUTTON_BSP_FILE_PATH一眼看懂含义。
  • sysfs 文件路径抽成常量,禁止代码内裸写字符串。

3. 日志可读性

  • 不直接打印原始数字 0/1,转换为released / pressed可读文本再输出。
  • 日志统一使用英文,规避中文编码乱码问题。
  • 错误日志带上文件路径,方便问题定位。

4. 错误兜底(健壮性)

每一步增加异常保护分支:

  • 文件打开失败:输出警告日志 + return 退出
  • 文件读取失败(读到非数字):输出日志 + return 退出
  • 读到无效值 (-1):直接 return 退出
  • 变量初始化为‑1,规避未初始化变量风险

5. Unused variable 编译警告

变量声明之后,如果没有读取、打印、使用,编译器报Unused variable警告。 把button_state用于日志打印,警告就会消失。

五、编译 / 部署 / 调试 / 命令

编译

复制代码
./build.sh -p <> -m <>

注意使用正确平台参数,避免工具链不一致,出现error adding symbols: no more archived files链接错误。

部署(NFS 共享方式)

复制代码
# 设备挂载电脑NFS共享目录
mount -t nfs -o nolock <服务器IP>:/NFS /mnt

# 将编译产物拷贝到设备运行目录
cp /mnt/nxcore‑.../bin/* /home/nx/bin/ -r

重启服务

nxcore 直接执行 restart 经常会在 stop 阶段卡死挂起;推荐 kill 强杀再启动

复制代码
systemctl kill -s SIGKILL nxcore
systemctl start nxcore
systemctl status nxcore --no-pager | head -5

查看日志

复制代码
# 实时跟踪日志 + 过滤按钮相关日志
journalctl -u nxcore -f | grep "board button"
  • journalctl -u nxcore -f:实时查看 nxcore 服务完整日志
  • grep "board button":只过滤按钮相关输出

预期日志输出:

复制代码
board button status:released  # 未按下
board button status:pressed   # 按下
board button status:released  # 松开

六、Git 提交流程

标准操作流程

复制代码
#1. 查看状态
git branch
git status
git remote -v

#2. 从主干切功能分支
git checkout -b board-button upstream/dev‑xxx

#3. 暂存业务代码(不要把build产物提交)
git add src/.../systemmanager.h src/.../systemmanager.cpp

#4. 首次配置git身份
git config --global user.email "..."
git config --global user.name "..."

#5. 项目脚本规范提交
./commit.sh   # 选 1(feat)/1(需求变更)/模块/机型(Arcadia)

#6. 推送远程分支
git push origin HEAD:board-button

误删代码恢复技巧

复制代码
git fetch upstream                     #拉取远程,不会改动本地文件
git show upstream/dev‑xxx:路径 | sed -n 'xx,yyp' #查看远程文件指定行

对照远程版本,只补回被误删的对应函数片段,不要整体 checkout 覆盖整个文件,防止冲掉自己新增代码。 经验:git fetch只拉取远程代码,不会修改本地工作区;不要直接 checkout 完整文件,会覆盖本地改动。

七、踩坑记录

问题 原因 解决办法
CI Pipeline failed 链接库损坏 / 编译工具链版本不一致 查看 CI 日志;重建损坏库,使用项目正确构建命令
命名不统一(函数 board / 常量 panel) 编码时命名没有保持语义统一 全部统一使用同一语义,本任务统一用 board
Unused variable button_state 变量读取之后没有打印使用 增加SYSMGR_INFO打印该变量
日志输出中文 编码、项目日志规范约束 全部日志使用英文输出
服务重启卡住 nxcore stop 阶段挂起 kill -s SIGKILL强杀进程,再 start 启动
误删原有业务逻辑 修改代码时误删原有逻辑 git fetch + git show对照远程版本,局部补回代码

八、总结与心得

  1. 仿照已有成熟代码最稳妥:项目存在同类业务代码,优先直接套用现有实现模式,代码风格、异常健壮性一步到位。
  2. 命名一致性:函数名、常量名语义要统一,避免自相矛盾。
  3. 路径抽常量:sysfs 文件路径不要裸写字符串,便于后期维护修改。
  4. 可读性输出:原始数值转换为可读文本之后再打印日志,不要直接输出 0/1。
  5. 事件机制边界理解:后端只负责 dispatch_event 发出事件;接收、监听逻辑全部交给前端;新增事件,枚举定义和前端监听两者都要配套。
  6. 分清职责边界:后端只管发事件,前端自己监听、解析数据,后端不用写前端业务代码。
  7. 区分环境问题和代码问题:CI 失败、链接库损坏、服务重启卡住,很多属于环境问题,先确认不是自己业务代码错误。

这份笔记覆盖 board 按钮读取任务,附带事件机制、Git、CI、部署排错完整流程,命令均为通用 Linux/Git 命令,仅供学习,无公司业务机密,可以作为个人实习学习笔记,无盈利性。

相关推荐
程序员小八77727 分钟前
后端转全栈:前端思维转变(Vue 视角)
前端·vue.js·状态模式
梦想的旅途21 小时前
基于企业微信API的微应用前端与后端架构设计
前端·状态模式·企业微信
烟漠河洛1 小时前
海外仓库存周转慢的破局点在于重构多仓数据同步架构
重构·状态模式
许彰午12 小时前
13-describe元数据输出
java·低代码·架构·状态模式
布莱克60515 小时前
如何实现断点续传和分片上传?
网络·tcp/ip·状态模式
leoZ23117 小时前
AI+前端提效- 06 AI辅助调试排错:前端报错、白屏、兼容问题极速定位
前端·人工智能·chatgpt·状态模式·超分辨率重建·openvino·dreamfusion
dsyuan0011 天前
ak-design 仿钉钉流程设计引擎图
钉钉·状态模式
国科安芯3 天前
轨道供电韧性:ASP4644四通道降压架构在低轨卫星平台电源管理中的适用性分析
运维·网络·数据库·嵌入式硬件·架构·状态模式·低轨卫星星座
听风吹等浪起3 天前
004:多个PDF合并成一个PDF【网页版】
pdf·状态模式