OH项目整体框架
- 应用层(applicatons/)
sample应该是应用样例,里面有cameraApp文件夹,相机应用 - 框架层(foundation/)
- 基础服务层(base)
- 系统能力层(systemabilitymgr)
- 运行时(arkcompiler/)
- 驱动框架(drivers/+hdf)
- 内核层(kernel/)
- 板级适配(device/board/xhilink/xhd100)
- 产品配置(vendor/xhilink/xhd100)
开发板
┌──────────── XH-D100 开发板(整块电路板)──────────────┐
│ │
│ ┌──────────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ RK3568 │ │ RK809 │ │AP6256 │ │RTL8168 │ │
│ │ 主控SoC │──→│PMIC │ │WiFi │ │以太网 │ │
│ │ (大脑) │ │ 音频 │ │蓝牙 │ │ │ │
│ └──────────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │DDR4 │ │eMMC │ │ MIPI屏 │ │USB口 │ │千兆网口│ │
│ │4GB │ │64GB │ │ │ │ │ │×2 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 扬声器 │ │ 麦克风 │ │ 摄像头 │ │RS485 │ │CAN口 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
└────────────────────────────────────────────────────────┘
** 局部功能分析**
相机应用
cameraApp/
├── src/main/
│ ├── cpp/ # C++ 源码(业务逻辑 + UI)
│ │ ├── camera_ability.h # Ability 生命周期声明
│ │ ├── camera_ability.cpp # Ability 生命周期实现
│ │ ├── camera_ability_slice.h # 主界面 AbilitySlice(UI + 交互)
│ │ ├── camera_ability_slice.cpp
│ │ ├── camera_manager.h # 相机硬件管理封装
│ │ ├── camera_manager.cpp
│ │ ├── event_listener.h # 通用点击/长按事件监听器
│ │ └── ui_config.h # UI 布局常量配置
│ ├── resources/base/media/ # UI 资源图片
│ │ ├── camera.png
│ │ ├── ic_back.png
│ │ ├── ic_camera_photo.png
│ │ ├── ic_camera_record.png
│ │ └── ... (共 12 个图标)
│ └── config.json # 应用配置清单
camera_manager
相机硬件管理
TestFrameStateCallback回调类,重写onfinish()虚函数,实例被SampleCameraStateMng拥有
工作机制
相机硬件完成一帧拍摄
↓
Camera 框架检测到帧完成
↓
调用 FrameStateCallback::OnFrameFinished() ← 虚函数分发
↓
执行 TestFrameStateCallback::OnFrameFinished() ← 你重写的实现
↓
在这里保存照片文件、更新状态等
主要类分工
| 类名 | 职责 |
|---|---|
SampleCameraManager |
顶层管理器,对外提供创建/预览/拍照/录像/暂停/停止接口 |
SampleCameraStateMng |
相机状态回调管理,处理相机创建、预览、录像、拍照的实际执行 |
TestFrameStateCallback |
帧回调处理,处理拍照完成事件 |
SampleCameraManager类
顶层管理类,操作封装暴露接口给ui层调用
SampleCameraManager::SampleCameraCreate()
获取cameraKit的单例->获取所有相机ID列表->检查列表是否为空->取第一个相机ID并校验->创建相机状态管理器->用该ID创建相机实例->创建保存目录
返回0成功,返回1失败。
我看这一部分逻辑他是直接取用获取列表ID的头一个进行判空操作,可能没有多摄像头或者切换摄像头的说法,只有后置摄像头。
SampleCameraManager::SampleCameraStart(Surface *surface)
启动相机预览,应该和以前摄像头操作一样从缓冲区拉取视频帧或者被动回调显示摄像头即时操作仅猜测,
TriggerLoopingCapture找到发现是虚函数,改写的位置在找,压根就没实现就只是一个虚函数。。。
UI 层 SampleCameraManager SampleCameraStateMng 相机框架
│ │ │ │
│ SampleCameraStart(surface) │ │ │
│─────────────────────────────────>│ │ │
│ │ StartPreview(surface) │ │
│ │───────────────────────────>│ │
│ │ │ new FrameConfig(PREVIEW) │
│ │ │ fc->AddSurface(surface) │
│ │ │ TriggerLoopingCapture(fc) │
│ │ │──────────────────────────>│
│ │ │ │
│ │ │ ← 持续写入帧到 Surface →│
│ ← UISurfaceView 自动从 Surface 读取并显示 ──────────────────────────────────────────────│
产品配置(vendor/xhilink/xhd100)
本项目适配rk3568(DAYU200),这个配置文件应该是厂商配置
| 目录 | 内容 | 性质 |
|---|---|---|
config.json |
产品定义:选哪些子系统/组件 | 厂商定制 |
bluetooth/ |
蓝牙固件(BCM4345C5.hcd)+ 驱动源码 | 硬件适配 |
hals/audio/ |
音频策略配置、ALSA 适配 | 硬件适配 |
hdf_config/khdf/ |
HDF 驱动配置(音频/摄像头/传感器/WiFi/振动器等) | 硬件适配 |
hdf_config/uhdf/ |
用户态驱动配置(摄像头/编解码/USB) | 硬件适配 |
etc/param/ |
硬件/产品参数 | 厂商定制 |
power_config/ |
电源模式/唤醒配置 | 厂商定制 |
preinstall-config/ |
预装/卸载应用列表 | 厂商定制 |
security_config/ |
安全配置(高权限进程/重启保护) | 厂商定制 |
window_config/ |
窗口/显示管理配置 | 厂商定制 |
resourceschedule/ |
资源调度/性能配置 | 厂商定制 |
image_conf/ |
系统镜像打包配置 | 厂商定制 |
default_app_config/ |
默认应用配置 | 厂商定制 |
板级适配(device/board/xhilink/xhd100)
audio_drivers/ -音频驱动
codec/ → RK809 编解码芯片驱动(A/D、D/A 转换)
-rk809_codec
--rk809_codec_impl 核心数据结构
struct Rk809ChipData {
struct CodecData codec; // HDF Codec 框架数据
struct DaiData dai; // HDF DAI 框架数据
struct HdfDeviceObject *hdev; // HDF 设备对象
struct platform_device *pdev; // Linux platform 设备
struct regmap *regmap; // 寄存器映射(I2C/SPI 访问芯片寄存器)
};
参数枚举
RK809SampleRateTimes-采样率倍频系数
| 枚举值 | 含义 |
|---|---|
RK809_SRT_00 = 0x00 |
采样率倍频系数 0 |
RK809_SRT_01 = 0x01 |
采样率倍频系数 1 |
RK809_SRT_02 = 0x02 |
采样率倍频系数 2 |
RK809_SRT_03 = 0x03 |
采样率倍频系数 3 |
RK809PLLInputCLKPreDIV-PLL输入时钟预分频
| 枚举值 | 分频比 |
|---|---|
RK809_PREMODE_1 = 0x03 |
1 分频 |
RK809_PREMODE_2 = 0x06 |
2 分频 |
RK809_PREMODE_3 = 0x0C |
4 分频 |
RK809_PREMODE_4 = 0x18 |
8 分频 |
RK809_VDW -音频数据位宽
| 枚举值 | 位宽 |
|---|---|
RK809_VDW_16BITS = 0x0F |
16 bit(0x0F = 15,实际位宽 = 寄存器值 + 1) |
RK809_VDW_24BITS = 0x17 |
24 bit(0x17 = 23) |
Updata_Dest-寄存器更新目标
| 枚举值 | 含义 |
|---|---|
UPDATE_LREG = 0 |
更新左声道寄存器 |
UPDATE_RREG = 1 |
更新右声道寄存器 |
DAI参数结构RK809DaiParamsVal
保存DAI(数字音频接口)的运行时参数
struct RK809DaiParamsVal {
uint32_t frequencyVal; // 采样频率
uint32_t DataWidthVal; // 数据位宽
};
录音路径(ADC工作):
麦克风 -> ADC ->SoC
(声波)->(模拟电信号)->(数字0/1)->处理/存储
播放路径(DAC工作):
DAC 扬声器
SoC------>(数字0/1)--------->模拟电信号--------->声波
SoC VS Codec VS Dai
┌──────── RK3568 (SoC) ────────┐ ┌──── RK809 (Codec芯片) ────┐
│ │ │ │
│ I2S 控制器 (DAI 主端) ←──── I2S总线 ────→ I2S 控制器 (DAI 从端)│
│ │ │ ADC (模拟→数字) │
│ CPU 处理音频数据 │ │ DAC (数字→模拟) │
│ │ │ 模拟增益/音量 │
└───────────────────────────────┘ └────────────────────────────┘
驱动接口函数
codec侧(编解码芯片控制)
| 函数 | 功能 |
|---|---|
GetCodecDevice() |
获取 RK809 芯片数据单例 |
Rk809DeviceInit() |
芯片初始化(配置寄存器默认值) |
Rk809DeviceRegRead() |
读芯片寄存器(底层) |
Rk809DeviceRegWrite() |
写芯片寄存器(底层) |
RK809CodecReadReg() |
Codec 框架层读寄存器 |
Rk809CodecWriteReg() |
Codec 框架层写寄存器 |
Rk809RegBitsUpdate() |
更新寄存器指定位域(按位修改,不影响其他位) |
Rk809DeviceInit()函数里面有个CodecDeviceInitRegConfig函数比较关键,这个函数会从获取初始参数存入到配置表initCfg,再逐行写入到寄存器完成初始化配置,每写一次会休息一下,配置表参数存放在vendor下面的hcs文件中
函数中有参数没用到我看他是只写出来不用,忽略警告用
DAI侧(数字音频接口控制)
| 函数 | 功能 |
|---|---|
Rk809DaiDeviceInit() |
DAI 初始化 |
Rk809DaiStartup() |
DAI 启动 |
Rk809DaiHwParams() |
配置硬件参数(采样率、位宽等) |
Rk809NormalTrigger() |
触发控制(启动/停止/暂停/恢复) |
RK809CodecDaiReadReg() |
DAI 寄存器读 |
RK809CodecDaiWriteReg() |
DAI 寄存器写 |
DAI侧相对于codec侧初始化的相关函数只写了判定,这个要等到上层HwParams调用才能判定,位宽多少,采样率多少要运行时判定
函数返回值可能是负数,但位宽一定是正数,所以设置变量的时候函数返回值是int32_t类型而位宽是uint32_t
最核心的其实是Rk809DaiHwParams和Rk809DaiHwParamsUpdate,Rk809DaiHwParams解析位宽选定参数组装DAI参数,用Rk809DaiHwParamsUpdate更新硬件寄存器。执行不同的操作时使用对应的配置表并操作寄存器
| 配置表 | 寄存器操作 | 用途 |
|---|---|---|
g_rk817RenderStartRegConfig |
DAC 使能 + I2S RX 启动 | 开始播放 |
g_rk817RenderStopRegConfig |
DAC 禁用 + I2S RX 停止 | 停止播放 |
g_rk817CaptureStartRegConfig |
ADC 使能 + I2S TX 启动 | 开始录音 |
g_rk817CaptureStopRegConfig |
ADC 禁用 + I2S TX 停止 | 停止录音 |
dai/ → RK3568 数字音频接口驱动(I2S/PCM)厂商提供的。
dsp/ → DSP 数字信号处理驱动
soc/ → DMA 直接内存访问驱动(音频数据搬运)
headset_monitor/ → 模拟耳机检测(ADC/GPIO 方式)
camera/ -摄像头驱动
| 子目录 | 功能 |
|---|---|
device_manager/ |
传感器管理:IMX600(索尼传感器)、RKISPv5(瑞芯微 ISP) |
driver_adapter/ |
V4L2 设备操作适配层 |
pipeline_core/ |
图像处理管线节点:缩放、编解码、EXIF、人脸检测 |
demo/ |
摄像头使用示例 |
kernel/ -内核构建
| 内容 | 说明 |
|---|---|
linux-5.10/ + linux-6.6/ |
支持两个内核版本 |
configs/product_defconfig |
内核编译配置(启用/禁用内核特性) |
files/arch/arm64/boot/dts/rockchip/ |
设备树文件(硬件描述) |
files/drivers/net/can/ |
CAN 总线驱动(瑞芯微定制) |
files/drivers/net/ethernet/realtek/ |
Realtek R8168 以太网驱动 |
patches/ |
内核补丁(如 00_xhd100_kernel.patch 是 xhd100 专用补丁) |
touchscreen/ |
触摸屏驱动(GT911) |
build_kernel.sh |
内核编译脚本 |
logo.bmp |
开机 Logo |