杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

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 观看"的闭环。

方案的核心设计意图:

  1. 以任务表驱动系统运行:app_main.c 通过 task_info_table 静态声明所有系统任务(优先级、栈、队列),配合 irq_info_table 在双核(CPU0/CPU1)上分配中断,既保证了 WiFi 收发、音视频编解码等实时性要求的任务不被饿死,又通过静态栈预分配避免动态内存碎片。
  2. 功能宏裁剪编译粒度:app_config.h 通过宏开关控制特性集合(视频缓冲模式、双路录像、RF TRIM 代码驻留位置等),使同一套代码可编译出不同 RAM/功能配比的产品(如无 SDRAM 封装的低成本版本)。
  3. 视频路径按帧率分策略:图传场景(≤20 帧)使用乒乓缓冲(PPBUF)模式,写卡录像或高帧率图传(>20 帧)则使用 lbuf 模式,双路模式可同时提供实时流与 SD 卡录像。
  4. 存储路径标准化:录像统一存放于 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.hYUV 采集接口头文件
include/led_eyes.hLED 指示灯(人眼)控制
include/net_video_rec.h网络视频录像接口
include/simple_avi_unpkg.hAVI 容器解包(录像回放解析)
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.cAC7911B(开发板/天线版)基础外设引脚、电源、时钟配置
board_7912A.cAC7912A主流 IPC 形态(参考 AC7912AB 智能 WiFi 摄像头规格书)
board_7916A.cAC7916A更高规格型号
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宏开关按 SDRAMRF 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宏开关0SD 卡通道使能(板级覆盖)
OTA_MAJOR/MINOR/PATCH整型1/3/0OTA 版本号(语义化版本)
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 性能。

扩展点

  1. 新增业务动作:在 include/action.h 声明动作、在 app_core 事件分发中注册处理函数,可复用现成的按键/网络事件机制;
  2. 切换芯片型号:新增 board/wl82/board_XXX.c 并同步 board_config.h,应用代码无需改动——板级与应用解耦是本方案的默认扩展路径;
  3. 视频路数与分辨率:通过 CONFIG_VIDEO1/2_ENABLE、CONFIG_VIDEO_REC_PPBUF_MODE、CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE 组合,可配置单路/双路/三路产品形态;
  4. 云平台对接:net_video_rec 与 TUTK 通道之间的接口是替换云平台的天然边界,接其他云(如阿里云,参考 lib/net/aliyun/dm_ipc.c)时可保持采集与编码层不变;
  5. 配网方式: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/(板级支持)
Prev
WiFi 摄像头方案
Next
WiFi 故事机方案