WiFi IPC 可视对讲方案
本页面介绍基于杰理 AC79NN 系列芯片(AC791N/AC7912A/AC7916A)的 WiFi IPC 可视对讲产品方案,涵盖 apps/wifi_ipc 应用的目录结构、系统启动与多任务架构、应用配置体系、视频采集与图传机制、网络协议集成、存储录像管理以及板级支持。
Purpose and Scope
本页面面向需要理解或二次开发该 WiFi IPC 方案的嵌入式工程师,系统地阐述 apps/wifi_ipc 应用从开机启动到业务运行的完整机制:
- 应用目录结构与模块划分:
app_main.c(主入口)、app_database.c(配置数据库)、get_yuv_data.c(视频数据采集)等模块的职责边界; - 系统任务与中断体系:
task_info_table中全部任务的优先级、栈大小与职责,以及中断在双核上的注册策略; - 应用配置体系:
app_config.h中影响编译行为的功能宏(视频缓冲模式、网络协议、OTA 版本等); - 视频采集与图传机制:乒乓缓冲(PPBUF)模式与实时流/录像双路模式的设计取舍;
- 网络与存储:TUTK/CTP 协议集成、DCIM/EMR 录像目录规划、SD 卡与 U 盘存储路径;
- 板级与构建:AC7911B/AC7912A/AC7916A 三套板级文件与 Makefile/cbp 工程组织方式。
不在本页范围:底层 WiFi 协议栈(lwIP、RtmpMlmeTask)的细节请参考网络协议相关文档;音频编解码器(speex/opus/aec)的算法实现属于音频子系统;产测模式(CONFIG_MASS_PRODUCTION_ENABLE)与二维码配网(CONFIG_QR_CODE_NET_CFG)属于生产工具链专题。
概述
WiFi IPC(Internet Protocol Camera)可视对讲方案是杰理 AC79NN SDK 中面向智能摄像头、可视门铃、婴儿监视器等场景的完整产品级应用。方案以 AC791N 系列双核 MCU 为核心,集成 WiFi(802.11)、音视频采集编码(PCM/speex/opus/AEC)、网络传输(TUTK 云平台 + lwIP)、本地存储(SD/TF 卡录像)与 OTA 升级能力,形成一个"端侧采集 — 网络传输 — 云端/APP 观看"的闭环。
方案的核心设计意图:
- 以任务表驱动系统运行:
app_main.c通过task_info_table静态声明所有系统任务(优先级、栈、队列),配合irq_info_table在双核(CPU0/CPU1)上分配中断,既保证了 WiFi 收发、音视频编解码等实时性要求的任务不被饿死,又通过静态栈预分配避免动态内存碎片。 - 功能宏裁剪编译粒度:
app_config.h通过宏开关控制特性集合(视频缓冲模式、双路录像、RF TRIM 代码驻留位置等),使同一套代码可编译出不同 RAM/功能配比的产品(如无 SDRAM 封装的低成本版本)。 - 视频路径按帧率分策略:图传场景(≤20 帧)使用乒乓缓冲(PPBUF)模式,写卡录像或高帧率图传(>20 帧)则使用 lbuf 模式,双路模式可同时提供实时流与 SD 卡录像。
- 存储路径标准化:录像统一存放于
DCIM/1|2|3目录,紧急录像(EMR)独立子目录,方便 APP 端按目录枚举文件。
架构
下图展示了 WiFi IPC 可视对讲方案的整体分层架构,以及各模块之间的依赖关系(依据 apps/wifi_ipc 目录结构与 app_main.c 任务表绘制):
flowchart TD
subgraph sg_App["应用层 apps/wifi_ipc"]
AppMain["app_main.c<br/>任务表/中断表/事件分发"]
AppDB["app_database.c<br/>系统配置数据库"]
GetYUV["get_yuv_data.c<br/>YUV视频采集"]
NetVideoRec["net_video_rec.h<br/>网络视频录像"]
AviUnpkg["simple_avi_unpkg.h<br/>AVI解包"]
LedEyes["led_eyes.h<br/>指示灯控制"]
StorageDev["storage_device.h<br/>存储设备管理"]
end
subgraph sg_Middle["中间件/服务任务"]
AudioServer["audio_server<br/>audio_mix/decoder/encoder"]
Codecs["speex/opus/aec/dns/amr<br/>编码器任务"]
WifiStack["tasklet/RtmpMlmeTask<br/>RtmpCmdQTask/wl_rx_irq_thread"]
TcpIp["tcpip_thread<br/>lwIP 协议栈"]
UsbServer["usb_server/usb_msd0/1<br/>uac_play/record"]
OtaTask["update/dw_update<br/>OTA升级"]
WechatTask["wechat_task"]
end
subgraph sg_Net["网络/云"]
TUTK["TUTK 云平台<br/>CONFIG_NET_TUTK_ENABLE"]
CTP["CTP 配网协议<br/>CONFIG_CTP_ENABLE"]
end
subgraph sg_HW["硬件/存储"]
Flash[(SPI Flash<br/>CONFIG_DATABASE_2_FLASH)]
SdCard[(SD/TF 卡<br/>DCIM 录像目录)]
UsbDisk[(U 盘)]
Camera["摄像头 Sensor<br/>YUV 数据"]
Rtc["RTC 时钟"]
end
AppMain --> AudioServer
AppMain --> WifiStack
AppMain --> OtaTask
AppMain --> UsbServer
AppMain --> AppDB
AppMain --> GetYUV
AppMain --> NetVideoRec
AppMain --> StorageDev
GetYUV --> Camera
NetVideoRec --> SdCard
StorageDev --> SdCard
StorageDev --> UsbDisk
AppDB --> Flash
WifiStack --> TcpIp
TcpIp --> TUTK
TcpIp --> CTP
Codecs --> AudioServer
LedEyes --> AppMain
AviUnpkg --> NetVideoRec
架构说明:
- 应用层(
apps/wifi_ipc)是方案的门面:app_main.c定义了系统的任务表与中断表,是系统启动的根;app_database.c负责把用户配置持久化到 SPI Flash(CONFIG_DATABASE_2_FLASH);get_yuv_data.c从摄像头 Sensor 获取 YUV 数据供预览/编码;net_video_rec与simple_avi_unpkg组成网络录像与回放链路;led_eyes提供指示灯(人眼状态)反馈。 - 中间件层是 SDK 提供的能力集合:音频服务器与各类编码器任务(speex/opus/aec/dns/amr)服务于对讲语音;WiFi 相关任务(
tasklet、RtmpMlmeTask、RtmpCmdQTask、wl_rx_irq_thread)负责 802.11 MAC/MLME 与收包;tcpip_thread承载 lwIP 协议栈;update/dw_update提供 OTA;usb_server系列支持 UAC 音频与 MSD 存储。 - 网络/云:通过 TUTK(
CONFIG_NET_TUTK_ENABLE)对接云平台实现 APP 远程观看与对讲,CTP(CONFIG_CTP_ENABLE)提供配网能力。 - 硬件/存储:录像写入 SD/TF 卡的
DCIM目录,配置存于 SPI Flash,摄像头通过并行接口送入 YUV 数据。
应用目录结构
apps/wifi_ipc 是独立的可编译应用,目录组织如下(依据仓库实际文件):
| 文件 | 职责 |
|---|---|
app_main.c | 主入口:中断表、静态任务栈、task_info_table 任务表、事件分发 |
app_database.c | 系统配置数据库读写(配合 CONFIG_DATABASE_2_FLASH 存 Flash) |
get_yuv_data.c | 摄像头 YUV 数据采集,供视频预览/图传/编码使用 |
board/wl82/ | WL82 板级支持:board_7911B_develop_aerial.c、board_7912A.c、board_7916A.c、board_config.h、Makefile、AC791N_WIFI_IPC.cbp |
include/action.h | 应用动作(Action)表声明 |
include/app_config.h | 应用功能宏配置(视频/网络/存储/OTA) |
include/board.h | 板级接口声明 |
include/dev_desc.h | 设备描述符 |
include/ename.h | 事件名定义 |
include/get_yuv_data.h | YUV 采集接口头文件 |
include/led_eyes.h | LED 指示灯(人眼)控制 |
include/net_video_rec.h | 网络视频录像接口 |
include/simple_avi_unpkg.h | AVI 容器解包(录像回放解析) |
include/storage_device.h | 存储设备(SD/U 盘)管理接口 |
目录设计意图:include/ 集中暴露模块接口,board/ 按芯片型号拆分板级差异,业务逻辑与板级配置解耦——同一套业务代码可通过 board_config.h 切换 AC7911B/AC7912A/AC7916A 三种硬件。
系统启动与多任务体系
中断表与双核注册策略
app_main.c 首先声明中断表 irq_info_table,它决定了每个中断注册到哪个 CPU 核以及中断优先级。方案支持双核(CPU_CORE_NUM > 1)与单核两种运行形态:
/*中断列表 */
const struct irq_info irq_info_table[] = {
//中断号 //优先级0-7 //注册的cpu(0或1)
#ifdef CONFIG_IPMASK_ENABLE
//不可屏蔽中断方法:支持写flash,但中断函数和调用函数和const要全部放在内部ram
{ IRQ_SOFT5_IDX, 6, 0 }, //此中断强制注册到cpu0
{ IRQ_SOFT4_IDX, 6, 1 }, //此中断强制注册到cpu1
#endif
#if CPU_CORE_NUM == 1
{ IRQ_SOFT5_IDX, 7, 0 }, //此中断强制注册到cpu0
{ IRQ_SOFT4_IDX, 7, 1 }, //此中断强制注册到cpu1
{ -2, -2, -2 },//如果加入了该行, 那么只有该行之前的中断注册到对应核, 其他所有中断强制注册到CPU0
#endif
{ IRQ_SPI1_IDX, 7, 1 },//中断强制注册到cpu0/1
{ IRQ_PAP_IDX, 7, 1 },//中断强制注册到cpu0/1
{ IRQ_EMI_IDX, 7, 1 },//中断强制注册到cpu0/1
{ -1, -1, -1 },
};
Source: app_main.c
设计意图说明:
IRQ_SPI1_IDX、IRQ_PAP_IDX、IRQ_EMI_IDX被强制注册到 CPU1,让占用带宽的 SPI 外设中断与 EMI(外部内存接口)中断与 CPU0 上的主业务(应用逻辑、WiFi 栈)隔离,减少关键路径被打断的时长;- 单核形态下(
CPU_CORE_NUM == 1),通过哨兵行{ -2, -2, -2 }声明"该行之前的中断按各自核注册,之后的中断全部强制注册到 CPU0",保证单核运行时中断归属一致; - 中断表以
{ -1, -1, -1 }结尾,驱动层据此遍历表项完成注册。
静态任务栈与任务表
为保证内存确定性,方案为关键任务预分配静态栈(ALIGNE(4) 对齐),避免运行期动态分配失败导致系统崩溃:
/*创建使用 os_task_create_static 或者task_create 接口的 静态任务堆栈*/
#define SYS_TIMER_STK_SIZE 512
#define SYS_TIMER_Q_SIZE 128
static u8 sys_timer_tcb_stk_q[sizeof(StaticTask_t) + SYS_TIMER_STK_SIZE * 4 + sizeof(struct task_queue) + SYS_TIMER_Q_SIZE] ALIGNE(4);
#define APP_CORE_STK_SIZE 2048
#define APP_CORE_Q_SIZE 2048
static u8 app_core_tcb_stk_q[sizeof(StaticTask_t) + APP_CORE_STK_SIZE * 4 + sizeof(struct task_queue) + APP_CORE_Q_SIZE] ALIGNE(4);
/*创建使用 thread_fork 接口的 静态任务堆栈*/
#define WIFI_TASKLET_STK_SIZE 1400
static u8 wifi_tasklet_tcb_stk_q[sizeof(struct thread_parm) + WIFI_TASKLET_STK_SIZE * 4] ALIGNE(4);
Source: app_main.c
随后 task_info_table 将全部任务(含静态栈任务与动态栈任务)统一登记,SDK 内核在启动阶段按此表逐个创建任务:
/*任务列表 */
const struct task_info task_info_table[] = {
{"init", 30, 512, 256 },
{"app_core", 22, APP_CORE_STK_SIZE, APP_CORE_Q_SIZE, app_core_tcb_stk_q },
{"sys_event", 30, SYS_EVENT_STK_SIZE, 0, sys_event_tcb_stk_q},
{"systimer", 16, SYSTIMER_STK_SIZE, 0, systimer_tcb_stk_q },
{"sys_timer", 10, SYS_TIMER_STK_SIZE, SYS_TIMER_Q_SIZE, sys_timer_tcb_stk_q},
{"audio_server", 16, 1024, 256 },
{"audio_mix", 27, 512, 64 },
{"audio_decoder", 30, 1024, 64 },
{"audio_encoder", 14, 1024, 64 },
{"speex_encoder", 10, 1024, 0 },
{"opus_encoder", 10, 1536, 0 },
{"aec_encoder", 13, 1024, 0 },
{"dns_encoder", 13, 512, 0 },
{"vir_dev_task", 9, 1024, 0 },
{"wechat_task", 18, 2048, 64 },
{"amr_encoder", 16, 1024, 0 },
{"usb_server", 20, 1024, 64 },
{"usb_msd0", 1, 512, 128 },
{"usb_msd1", 1, 512, 128 },
{"uac_play0", 26, 512, 32 },
{"uac_play1", 26, 512, 32 },
{"uac_record0", 26, 512, 0 },
{"uac_record1", 26, 512, 0 },
{"update", 21, 512, 32 },
{"dw_update", 21, 512, 32 },
{"tcpip_thread", 16, 800, 0 },
#ifdef CONFIG_WIFI_ENABLE
{"tasklet", 10, WIFI_TASKLET_STK_SIZE, 0, wifi_tasklet_tcb_stk_q },//通过调节任务优先级平衡WIFI收发占据总CPU的比重
{"RtmpMlmeTask", 16, WIFI_MLME_STK_SIZE, 0, wifi_mlme_tcb_stk_q },
{"RtmpCmdQTask", 16, WIFI_CMDQ_STK_SIZE, 0, wifi_cmdq_tcb_stk_q },
{"wl_rx_irq_thread", 5, WIFI_RX_STK_SIZE, 0, wifi_rx_tcb_stk_q },
#endif
{"btencry", 14, 512, 128 },
{"btctrler", 19, 512, 384 },
{"btstack", 18, 768, 384 },
};
Source: app_main.c
任务表中值得注意的设计点:
- 优先级是调优杠杆:
tasklet(WiFi 收发主任务)优先级 10,注释明确"通过调节任务优先级平衡 WIFI 收发占据总 CPU 的比重"——在视频图传场景中,WiFi 吞吐与音视频编码争抢 CPU,此优先级直接影响帧率与流畅度; wl_rx_irq_thread优先级最低(5):收包中断只做最轻量的入队,实际协议处理下沉到低优先级线程,避免高优先级任务长时间霸占 CPU;- 静态栈任务集中:
app_core(2KB)、WiFi 四任务、系统定时器任务均使用静态栈,保证这些关键路径不因堆碎片而启动失败; - 编码器任务按需存在:
speex_encoder/opus_encoder/aec_encoder/dns_encoder/amr_encoder对应不同对讲/录音编码格式,配合app_config.h中的CONFIG_PCM_ENC_ENABLE、CONFIG_AEC_ENC_ENABLE等宏启用。
任务职责总览
flowchart TD
subgraph sg_System["系统基础任务"]
Init["init<br/>优先级30"]
AppCore["app_core<br/>优先级22 静态栈2KB"]
SysEvent["sys_event<br/>优先级30"]
SysTimer["systimer / sys_timer<br/>优先级16/10"]
end
subgraph sg_Audio["音频任务"]
AudioServer["audio_server<br/>优先级16"]
AudioMix["audio_mix<br/>优先级27"]
AudioDec["audio_decoder<br/>优先级30"]
AudioEnc["audio_encoder<br/>优先级14"]
Speex["speex_encoder<br/>优先级10"]
Opus["opus_encoder<br/>优先级10"]
Aec["aec_encoder<br/>优先级13"]
end
subgraph sg_Wifi["WiFi/网络任务"]
Tasklet["tasklet<br/>优先级10 静态栈"]
RtmpMlme["RtmpMlmeTask<br/>优先级16"]
RtmpCmdQ["RtmpCmdQTask<br/>优先级16"]
WlRx["wl_rx_irq_thread<br/>优先级5"]
TcpIp["tcpip_thread<br/>优先级16"]
end
subgraph sg_Usb["USB 任务"]
UsbServer["usb_server<br/>优先级20"]
UsbMsd["usb_msd0/1<br/>优先级1"]
UacPlay["uac_play0/1<br/>优先级26"]
UacRec["uac_record0/1<br/>优先级26"]
end
subgraph sg_Ota["升级任务"]
Update["update<br/>优先级21"]
DwUpdate["dw_update<br/>优先级21"]
end
Init --> AppCore
AppCore --> SysEvent
AudioServer --> AudioMix
AudioServer --> AudioDec
AudioServer --> AudioEnc
AudioEnc --> Speex
AudioEnc --> Opus
AudioEnc --> Aec
Tasklet --> RtmpMlme
Tasklet --> RtmpCmdQ
Tasklet --> WlRx
RtmpCmdQ --> TcpIp
优先级数值越小优先级越高(0 为最高)。系统采用"高优先级驱动、低优先级处理"的经典嵌入式模式:例如音频服务器(16)调度编解码任务,wl_rx_irq_thread(5)仅做收包入队,把重活交给 tasklet/RtmpMlmeTask。
应用配置体系
apps/wifi_ipc/include/app_config.h 是方案所有编译期特性开关的汇聚点。它首先处理"无 SDRAM 封装"的低成本变体,然后按网络、视频、存储三组宏展开:
#ifdef CONFIG_NO_SDRAM_ENABLE /* 封装不带sdram就打开该宏 */
#undef __SDRAM_SIZE__
#define __SDRAM_SIZE__ (0 * 1024 * 1024)
#endif
#define CONFIG_NET_USR_ENABLE
#define NET_USR_PATH
#define CONFIG_DATABASE_2_FLASH /* 系统配置存flash */
#define CONFIG_DEBUG_ENABLE /* 打印开关 */
#define CONFIG_RTC_ENABLE /*RTC使能*/
#define CONFIG_PCM_DEC_ENABLE
#define CONFIG_PCM_ENC_ENABLE
/* #define CONFIG_AEC_ENC_ENABLE */
// #define CONFIG_DNS_ENC_ENABLE
#define CONFIG_NET_TUTK_ENABLE
#ifdef CONFIG_NET_ENABLE
#define CONFIG_CTP_ENABLE
#define CONFIG_WIFI_ENABLE /* 无线WIFI */
#ifdef CONFIG_NO_SDRAM_ENABLE
#define CONFIG_RF_TRIM_CODE_MOVABLE //把RF TRIM 的运行代码动态加载到ram运行(节省4K ram内存), 防止RF TRIM 期间500ms大电流访问flash造成flash挂掉持续大电流
#else
#define CONFIG_RF_TRIM_CODE_AT_RAM //把RF TRIM 的运行代码定死到ram运行(浪费4K ram内存,否则若动态加载到sdram需清cache), 防止RF TRIM 期间500ms大电流访问flash造成flash挂掉持续大电流
#endif
#endif
//#define CONFIG_OSD_ENABLE /* 视频OSD时间戳开关 */
#define CONFIG_VIDEO_REC_PPBUF_MODE /*视频使用乒乓BUF模式(图传<=20帧),关闭则用lbuf模式(图传>20帧和写卡录像),缓冲区大小配置video_buf_config.h*/
//#define CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE /* 视频支持双路莫模式(一路实时流、一路录SD卡)*/
// #define CONFIG_QR_CODE_NET_CFG //二维码配网
Source: app_config.h
录像目录与升级版本
方案为录像规划了标准目录树,并支持三路视频(THREE_WAY_ENABLE)与紧急录像(EMR):
#define OTA_MAJOR 1
#define OTA_MINOR 3
#define OTA_PATCH 0
#define CONFIG_REC_DIR_0 "DCIM/1/"
#define CONFIG_REC_DIR_1 "DCIM/2/"
#ifndef CONFIG_VIDEO1_ENABLE
#define CONFIG_REC_DIR_2 "DCIM/2/"
#else
#define CONFIG_REC_DIR_2 "DCIM/3/"
#endif
#define CONFIG_ROOT_PATH CONFIG_STORAGE_PATH"/C/"
#define CONFIG_REC_PATH_0 CONFIG_STORAGE_PATH"/C/"CONFIG_REC_DIR_0
#define CONFIG_REC_PATH_1 CONFIG_STORAGE_PATH"/C/"CONFIG_REC_DIR_1
#define CONFIG_REC_PATH_2 CONFIG_STORAGE_PATH"/C/"CONFIG_REC_DIR_2
#define CONFIG_UDISK_STORAGE_PATH "storage/usb_disk"
#define CONFIG_UDISK_ROOT_PATH CONFIG_UDISK_STORAGE_PATH"/C/"
#ifdef CONFIG_EMR_DIR_ENABLE
#define CONFIG_EMR_REC_DIR "EMR/"
#define CONFIG_EMR_REC_DIR_0 "DCIM/1/"CONFIG_EMR_REC_DIR
#define CONFIG_EMR_REC_DIR_1 "DCIM/2/"CONFIG_EMR_REC_DIR
#define CONFIG_EMR_REC_DIR_2 "DCIM/3/"CONFIG_EMR_REC_DIR
#endif
#define CAMERA0_CAP_PATH CONFIG_REC_PATH_0
#define CAMERA1_CAP_PATH CONFIG_REC_PATH_1
#define CAMERA2_CAP_PATH CONFIG_REC_PATH_2
#define MAX_FILE_NAME_LEN 64
#define FILE_SHOW_NUM 12 /* 一页显示文件数 */
Source: app_config.h
设计意图:
CONFIG_REC_PATH_*与CAMERA*_CAP_PATH统一:录像路径同时作为拍照(Capture)路径,保证 APP 端按DCIM/N枚举即可同时拿到录像与照片;- EMR 目录嵌套于 DCIM 子目录:紧急事件录像(如门铃触发)与普通录像分区存放但共享根目录,便于按时间线检索;
- 版本号三位一体:
OTA_MAJOR/MINOR/PATCH遵循语义化版本——次版本必须向下兼容,修订版本用于 BUG 修复,这约束了 OTA 差分升级的兼容性边界。
视频采集与图传机制
YUV 数据采集
get_yuv_data.c 是视频链路的源头模块(对应头文件 include/get_yuv_data.h),负责从摄像头 Sensor 获取 YUV 原始数据,为预览、图传编码、录像编码提供统一的视频帧来源。该模块独立成文件的设计意图是:将 Sensor 时序、DMA 搬运、缓冲切换等硬件相关逻辑与上层业务(编码、网络)隔离,上层只通过 get_yuv_data.h 声明的接口获取帧数据。
乒乓缓冲(PPBUF)与 lbuf 模式
app_config.h 中 CONFIG_VIDEO_REC_PPBUF_MODE 是视频路径最关键的决策宏:
#define CONFIG_VIDEO_REC_PPBUF_MODE /*视频使用乒乓BUF模式(图传<=20帧),关闭则用lbuf模式(图传>20帧和写卡录像),缓冲区大小配置video_buf_config.h*/
//#define CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE /* 视频支持双路莫模式(一路实时流、一路录SD卡)*/
Source: app_config.h
两种缓冲模式的选择依据(源码注释明确给出):
| 模式 | 适用场景 | 特点 |
|---|---|---|
| PPBUF(乒乓缓冲) | 图传 ≤ 20 帧 | 两块缓冲区交替使用:Sensor DMA 写入一块的同时,编码器读取另一块,避免帧级阻塞,延迟低 |
| lbuf(链式缓冲) | 图传 > 20 帧、写卡录像 | 动态链式缓冲池,可容纳更多在途帧,吞吐高但延迟略大 |
缓冲区大小统一在 video_buf_config.h 中配置,与 app_config.h 解耦,方便不同分辨率/帧率的产品快速调参。
双路录制模式
CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE(默认关闭)启用"一路实时流 + 一路录 SD 卡"的双路模式:同一份 YUV 数据被两条独立编码流水线消费,一路低码率送网络(保证图传流畅),一路高码率写卡(保证本地画质)。这是可视门铃类产品的典型需求——访客按下门铃时既要本地留证,又要远程实时查看。该宏与 CONFIG_VIDEO1_ENABLE/CONFIG_VIDEO2_ENABLE 配合,最多支持三路视频(THREE_WAY_ENABLE、CONFIG_VIDEO_REC_NUM 3)。
视频链路数据流
flowchart LR
Sensor["摄像头 Sensor"] -->|"YUV 原始数据"| GetYUV["get_yuv_data.c<br/>采集/缓冲管理"]
GetYUV -->|"PPBUF/lbuf 帧"| Encoder["video 编码器"]
Encoder --> Preview["本地预览/OSD"]
Encoder -->|"低码率流"| NetVideoRec["net_video_rec<br/>网络视频传输"]
Encoder -->|"高码率流"| SdRecord["SD 卡录像<br/>DCIM/N/"]
SdRecord --> AviUnpkg["simple_avi_unpkg<br/>AVI 回放解析"]
NetVideoRec --> TUTK
网络协议与云平台
TUTK 云平台
CONFIG_NET_TUTK_ENABLE 启用 TUTK 协议栈——这是本方案实现"APP 远程观看/对讲"的核心通道。TUTK 提供 P2P 打洞与中继转发能力,使设备无需公网 IP 即可被手机 APP 直连。对讲语音流与视频流均承载于该通道之上。
CTP 配网与 WiFi 使能
#ifdef CONFIG_NET_ENABLE
#define CONFIG_CTP_ENABLE
#define CONFIG_WIFI_ENABLE /* 无线WIFI */
#ifdef CONFIG_NO_SDRAM_ENABLE
#define CONFIG_RF_TRIM_CODE_MOVABLE //把RF TRIM 的运行代码动态加载到ram运行(节省4K ram内存), 防止RF TRIM 期间500ms大电流访问flash造成flash挂掉持续大电流
#else
#define CONFIG_RF_TRIM_CODE_AT_RAM //把RF TRIM 的运行代码定死到ram运行(浪费4K ram内存,否则若动态加载到sdram需清cache), 防止RF TRIM 期间500ms大电流访问flash造成flash挂掉持续大电流
#endif
#endif
Source: app_config.h
CONFIG_CTP_ENABLE:CTP 配网协议,设备通过热点/广播方式接收路由器 SSID/密码;CONFIG_RF_TRIM_CODE_MOVABLE / AT_RAM:RF 校准(TRIM)期间有约 500ms 的大电流 Flash 访问窗口,若代码运行在外部 SDRAM 上访问 Flash 会因 cache 失效造成 Flash 挂掉。方案提供两种规避:无 SDRAM 封装动态加载到内部 RAM(省 4K),有 SDRAM 封装定死到 RAM(浪费 4K 但免 cache 清刷)。这是硬件成本与健壮性的权衡点。
存储与录像管理
录像路径以 CONFIG_STORAGE_PATH 为根,SD 卡默认使能(TCFG_SD0_ENABLE/TCFG_SD1_ENABLE 默认 0,需在板级配置打开),并支持 U 盘存储(CONFIG_UDISK_STORAGE_PATH)。storage_device.h 抽象了 SD 卡与 U 盘的挂载/卸载,net_video_rec 负责将编码流封装写盘,simple_avi_unpkg 提供 AVI 容器解析用于本地回放。
核心流程
开机启动流程
系统上电后按"中断表 → 静态栈 → 任务表 → 应用动作"的顺序完成初始化:
sequenceDiagram
participant Boot as 启动代码
participant Irq as 中断表 irq_info_table
participant Task as task_info_table
participant App as app_core 任务
participant DB as app_database
participant Wifi as WiFi 任务组
participant Cloud as TUTK 云平台
Boot->>Irq: 注册中断(SPI1/PAP/EMI → CPU1)
Boot->>Task: 创建任务(按优先级/栈大小)
Task->>App: 启动 app_core 应用任务
App->>DB: 读取系统配置(Flash)
DB-->>App: 配置(录像路径/网络参数)
App->>Wifi: 启动 WiFi(tasklet/RtmpMlme/Rx)
Wifi->>Cloud: CTP 配网 / TUTK 上线
App->>App: 进入事件循环(等待按键/网络/录像事件)
对讲呼叫流程
访客按下门铃或 APP 发起呼叫后,设备端的事件流如下:
sequenceDiagram
participant Key as 按键/门铃事件
participant App as app_core
participant YUV as get_yuv_data
participant Enc as 音视频编码器
participant Net as net_video_rec
participant Cloud as TUTK 通道
participant App2 as 手机APP
Key->>App: 门铃事件(enet/按键)
App->>YUV: 启动视频采集(PPBUF模式)
App->>Enc: 启动音频编码(speex/opus)
YUV->>Enc: YUV帧 + PCM帧
Enc->>Net: 编码后的音视频流
Net->>Cloud: 封装TUTK协议发送
Cloud-->>App2: 推流到APP(实时画面+语音)
App2->>App: 双向对讲(下行语音)
App->>App: 同时写卡录像(DCIM/EMR)
设计要点:呼叫事件驱动整条链路按需启动(采集→编码→传输),挂断后停止编码并落盘索引,既降低空闲功耗,也避免长期占用编码器资源。紧急事件(如门铃触发)通过 EMR 目录单独留证。
板级支持与构建
board/wl82/ 目录按芯片型号拆分板级文件:
| 文件 | 目标芯片 | 说明 |
|---|---|---|
board_7911B_develop_aerial.c | AC7911B(开发板/天线版) | 基础外设引脚、电源、时钟配置 |
board_7912A.c | AC7912A | 主流 IPC 形态(参考 AC7912AB 智能 WiFi 摄像头规格书) |
board_7916A.c | AC7916A | 更高规格型号 |
board_config.h | 通用 | 板级宏开关(TCFG_SD0_ENABLE 等) |
Makefile / AC791N_WIFI_IPC.cbp | 构建 | Makefile 命令行构建 + Code::Blocks 工程 |
app_config.h 顶部 #include "board_config.h",使应用配置能感知板级能力(如 SD 卡引脚是否启用、是否带 SDRAM),实现"一套应用代码、多板卡适配"。
配置选项汇总
以下为 apps/wifi_ipc/include/app_config.h 中定义的方案级配置(依据源码逐项核对):
| 配置项 | 类型 | 默认 | 说明 |
|---|---|---|---|
CONFIG_NO_SDRAM_ENABLE | 宏开关 | 关 | 无 SDRAM 封装变体,__SDRAM_SIZE__ 置 0 |
CONFIG_DATABASE_2_FLASH | 宏开关 | 开 | 系统配置持久化到 SPI Flash(app_database.c) |
CONFIG_DEBUG_ENABLE | 宏开关 | 开 | 调试打印使能 |
CONFIG_RTC_ENABLE | 宏开关 | 开 | RTC 时钟使能(录像时间戳依赖) |
CONFIG_PCM_DEC_ENABLE / CONFIG_PCM_ENC_ENABLE | 宏开关 | 开 | PCM 解码/编码使能 |
CONFIG_AEC_ENC_ENABLE | 宏开关 | 关 | 回声消除编码器(对讲免提建议打开) |
CONFIG_DNS_ENC_ENABLE | 宏开关 | 关 | DNS 编码器 |
CONFIG_NET_TUTK_ENABLE | 宏开关 | 开 | TUTK 云平台协议(APP 远程访问通道) |
CONFIG_NET_ENABLE | 宏开关 | — | 网络功能总开关(由外部配置) |
CONFIG_CTP_ENABLE | 宏开关 | 开 | CTP 配网协议 |
CONFIG_WIFI_ENABLE | 宏开关 | 开 | WiFi 无线使能 |
CONFIG_RF_TRIM_CODE_MOVABLE / AT_RAM | 宏开关 | 按 SDRAM | RF TRIM 代码驻留策略(RAM 节省 vs 稳定性) |
CONFIG_OSD_ENABLE | 宏开关 | 关 | 视频 OSD 时间戳叠加 |
CONFIG_VIDEO_REC_PPBUF_MODE | 宏开关 | 开 | 乒乓缓冲模式(图传 ≤20 帧) |
CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE | 宏开关 | 关 | 双路录制(实时流 + 录卡) |
CONFIG_QR_CODE_NET_CFG | 宏开关 | 关 | 二维码配网 |
CONFIG_VIDEO1/2_ENABLE | 宏开关 | 依型号 | 第二/第三路视频,均开则 THREE_WAY_ENABLE、CONFIG_VIDEO_REC_NUM=3 |
CONFIG_EMR_DIR_ENABLE | 宏开关 | 关 | 紧急录像 EMR 子目录 |
TCFG_SD0_ENABLE / TCFG_SD1_ENABLE | 宏开关 | 0 | SD 卡通道使能(板级覆盖) |
OTA_MAJOR/MINOR/PATCH | 整型 | 1/3/0 | OTA 版本号(语义化版本) |
CONFIG_REC_DIR_0/1/2 | 字符串 | "DCIM/1/" 等 | 录像目录名 |
CONFIG_REC_PATH_0/1/2 | 字符串 | storage/.../C/DCIM/N/ | 录像完整路径 |
CONFIG_UDISK_STORAGE_PATH | 字符串 | "storage/usb_disk" | U 盘存储根路径 |
MAX_FILE_NAME_LEN | 整型 | 64 | 文件名最大长度 |
FILE_SHOW_NUM | 整型 | 12 | 文件浏览一页显示数 |
故障模式、边界与并发
内存与并发风险点
- 静态栈是硬约束:
app_core栈仅 2KB,若在应用动作/事件回调中新增深递归或大局部数组,将直接栈溢出;扩展业务时应优先将重活下沉到独立任务; - WiFi 与编码器争抢 CPU:
tasklet优先级 10 高于audio_encoder(14),高负载图传下音频编码可能被抢占延迟,需通过调节tasklet优先级或帧率控制平衡; - RF TRIM 期间的 Flash 访问禁忌:校准期间 500ms 大电流访问 Flash 会挂掉,
CONFIG_RF_TRIM_CODE_MOVABLE/AT_RAM的选择必须与封装(有无 SDRAM)匹配,否则生产测试阶段会偶发死机; - 录像写卡与网络并发:PPBUF 模式仅适合 ≤20 帧图传,若同时写卡录像应改用 lbuf 模式或启用双路录制模式,否则缓冲溢出丢帧。
边界条件
- 单核形态(
CPU_CORE_NUM == 1)下中断表依赖{ -2, -2, -2 }哨兵行收敛注册范围,新增中断项必须放在该行之前,否则会被强制注册到 CPU0 而丢失原定核归属; CONFIG_VIDEO_REC_NUM与目录数联动:只有同时打开CONFIG_VIDEO1_ENABLE和CONFIG_VIDEO2_ENABLE才启用三路目录(DCIM/3/),目录宏与视频路数不一致会导致文件枚举错位;- 无 SDRAM 封装(
__SDRAM_SIZE__ = 0)时所有视频缓冲、协议栈内存只能取自内部 RAM,缓冲区大小(video_buf_config.h)必须按内部 RAM 余量收紧。
性能与运维
- 调优入口:WiFi 吞吐/CPU 占比通过
tasklet优先级调节(app_main.c注释明确说明);视频缓冲大小在video_buf_config.h配置,与app_config.h解耦; - 诊断手段:
CONFIG_DEBUG_ENABLE控制打印;RTOS_STACK_CHECK_ENABLE(默认开)定时检查任务栈使用,MEM_LEAK_CHECK_ENABLE可选开启内存泄漏检查; - 升级通道:
update/dw_update双升级任务支持 OTA,版本号遵循语义化规则保证差分升级兼容; - 产测预留:
CONFIG_MASS_PRODUCTION_ENABLE(默认关)与CONFIG_IPERF_ENABLE(默认关)分别用于产测模式与 WiFi 吞吐测试,量产前应打开验证 RF 性能。
扩展点
- 新增业务动作:在
include/action.h声明动作、在app_core事件分发中注册处理函数,可复用现成的按键/网络事件机制; - 切换芯片型号:新增
board/wl82/board_XXX.c并同步board_config.h,应用代码无需改动——板级与应用解耦是本方案的默认扩展路径; - 视频路数与分辨率:通过
CONFIG_VIDEO1/2_ENABLE、CONFIG_VIDEO_REC_PPBUF_MODE、CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE组合,可配置单路/双路/三路产品形态; - 云平台对接:
net_video_rec与 TUTK 通道之间的接口是替换云平台的天然边界,接其他云(如阿里云,参考lib/net/aliyun/dm_ipc.c)时可保持采集与编码层不变; - 配网方式:
CONFIG_CTP_ENABLE(默认)与CONFIG_QR_CODE_NET_CFG(关)可切换,或同时保留两种配网入口。
测试与验证建议
仓库未在 apps/wifi_ipc 内附带单元测试目录,验证主要依赖整机联调:
- 功能验证:对讲双向语音(speex/opus)、实时预览帧率(PPBUF ≤20 帧)、双路录制同时性、EMR 触发落盘;
- 稳定性验证:长时间挂机内存(开启
MEM_LEAK_CHECK_ENABLE)、任务栈余量(RTOS_STACK_CHECK_ENABLE)、WiFi 断连重连; - 量产验证:RF TRIM 流程(确认
RF_TRIM_CODE策略与封装匹配)、CONFIG_MASS_PRODUCTION_ENABLE产测项、OTA 差分升级回滚。
相关链接
- app_main.c(任务表/中断表)
- app_config.h(应用配置)
- get_yuv_data.c(视频采集)
- app_database.c(配置数据库)
- board_config.h(板级配置)
- AC7912AB IPC 硬件参考设计
- 相关目录:
apps/wifi_ipc/include/(接口头文件)、apps/wifi_ipc/board/wl82/(板级支持)