1. 源码文件树形结构
.
├── tang.c
├── tang_app.c
├── tang_key_function.c
├── tang_tts.c
├── tang_musicplayer.c
├── tang_ui.c (条件编译)
├── include/
├── modules/
│ ├── tang_module_linein.c
│ ├── tang_module_cloud_music.c
│ ├── tang_module_local_music.c (条件编译)
│ ├── tang_module_dmr.c (条件编译)
│ ├── tang_module_mulroom.c (条件编译)
│ ├── tang_module_airplay.c (条件编译)
│ ├── tang_module_bt.c (条件编译)
│ ├── tang_module_vr.c (条件编译)
│ ├── tang_module_camera.c (条件编译)
│ ├── camera/
│ │ ├── camera.c
│ │ ├── lcd.c
│ │ ├── video.c
│ │ ├── savebmp.c
│ │ └── convert.c
│ └── song_supplyer/
│ ├── speech.c
│ ├── ximalaya.c
│ └── jushang.c
├── misc/
│ ├── battery_capacity.c
│ ├── tts_baidu.c
│ ├── dms.c (条件编译)
│ └── lapsule_control.c (条件编译)
└── ingenicplayer/
├── appserver.c
├── ingenicplayer.c
└── device.c
2. 应用程序树形结构
tang (主程序)
├── 核心功能层
│ ├── 应用主循环 (tang_app.c)
│ ├── 按键处理 (tang_key_function.c)
│ ├── TTS引擎 (tang_tts.c)
│ └── 音乐播放器 (tang_musicplayer.c)
├── 模块层
│ ├── 音频输入模块
│ ├── 云音乐模块
│ ├── 本地音乐模块
│ ├── DMR (数字媒体渲染器)
│ ├── 多房间音频
│ ├── AirPlay模块
│ ├── 蓝牙模块
│ ├── 语音识别模块
│ ├── 摄像头模块
│ └── 歌曲供应商接口
└── 服务层
├── 电池管理
├── 报警服务
├── WebRTC处理
├── 设备管理服务
└── 胶囊控制
3. 设计思想树形结构
软件设计思想
├── 模块化架构
│ ├── 功能模块化 (每个功能独立模块)
│ ├── 条件编译机制
│ └── 插件式设计
├── 分层架构
│ ├── 核心层 (基础功能)
│ ├── 模块层 (业务功能)
│ └── 服务层 (系统服务)
├── 设计模式
│ ├── 策略模式 (TTS/VR供应商选择)
│ ├── 工厂模式 (歌曲供应商)
│ ├── 观察者模式 (事件处理)
│ ├── 外观模式 (模块接口统一)
│ └── 命令模式 (按键处理)
├── 配置驱动开发
│ ├── 编译时功能开关
│ ├── 供应商选择配置
│ └── 硬件适配配置
└── 跨平台考虑
├── MIPS架构优化
├── 库依赖抽象
└── 安装脚本适配
4. 软件架构分析
核心架构特征:
-
模块化插件架构 - 每个功能都是独立的模块,通过条件编译控制
-
事件驱动设计 - 基于libevent库,支持异步事件处理
-
多层抽象 - 硬件抽象层、功能模块层、应用逻辑层分离
使用的设计模式:
-
策略模式:TTS引擎、VR引擎、歌曲供应商可替换
-
工厂模式:根据不同配置创建不同的功能模块实例
-
外观模式:为复杂子系统提供统一接口
-
观察者模式:事件处理机制
5. 运行性能特征
性能优化措施:
-
编译优化 :
-O2优化级别,异步栈展开 -
内存管理:动态库加载,共享内存使用
-
并发处理 :多线程支持(
-lpthread),异步事件处理 -
硬件加速:使用专用音频处理库(resample, alsa)
性能关键点:
-
音频处理:重采样、WebRTC音频处理
-
网络通信:UPnP、AirPlay、云服务
-
多媒体播放:硬件解码优化
-
实时性:语音识别响应、按键处理
6. 系统依赖分析
核心依赖库:
-
levent- 事件驱动框架 -
lplayer- 音频播放 -
ljson-c- 数据解析 -
lasound- 音频系统 -
lpthread- 多线程
功能专用库:
-
语音识别(TTS/VR):百度、捷通、思必驰等
-
网络服务:UPnP、AirPlay、WebRTC
-
多媒体:PNG解码、摄像头处理
-
系统服务:电源管理、WiFi、共享内存
这个设计体现了嵌入式Linux系统软件的典型特征:模块化、可配置、资源受限环境优化,以及面向多种硬件变体的适配能力。
Makefile架构:
# 获取当前工作目录的绝对路径
DIR_CUR := $(shell pwd)
# 自定义函数:字符串截取
# $1: string - 要截取的字符串
# $2: start pos - 起始位置
# $3: length - 截取长度
define substring
$(shell echo `expr substr $(1) $(2) $(3)`)
endef
# 功能模块开关定义,使用?=表示如果未定义则赋默认值0(关闭)
BT ?= 0 # 蓝牙功能开关
VR ?= 0 # 语音识别功能开关
TTS ?= 0 # 文本转语音功能开关
LAPSULE ?= 0 # 胶囊控制功能开关
INGENICPLAYER ?= 0 # 播放器功能开关(保留,可能需替换)
DMR ?= 0 # 数字媒体渲染器功能开关
WEBRTC ?= 0 # WebRTC音频处理功能开关
DMS ?= 0 # 设备管理服务功能开关
AIRPLAY ?= 0 # AirPlay功能开关
LOCALPLAYER ?= 0 # 本地播放器功能开关
ALARM ?= 0 # 闹钟功能开关
MULROOM ?= 0 # 多房间音频功能开关
CAMERA ?= 0 # 摄像头功能开关
# RK3568 Linux 64位交叉编译工具链定义
CC = aarch64-linux-gnu-gcc # ARM64架构C编译器
CXX = aarch64-linux-gnu-g++ # ARM64架构C++编译器
STRIP = aarch64-linux-gnu-strip # 二进制文件strip工具
INSTALL = install # 安装命令
DESTDIR = # 目标目录前缀(为空表示根目录)
PREFIX = /usr # 安装前缀目录
INITDIR = /etc/init.d/ # 初始化脚本目录
SBINDIR = $(PREFIX)/sbin # 系统二进制文件目录
# 源代码文件列表定义
SRCS = tang.c tang_app.c tang_key_function.c tang_tts.c tang_musicplayer.c # 核心源文件
SRCS += misc/battery_capacity.c # 电池容量检测
SRCS += modules/tang_module_linein.c # 线性输入模块
# 通用编译选项
CFLAGS = -fPIC -Wall -Werror -g -O2 -I. -I./include/ -I./modules/ -I$(MOLIB_DIR)/usr/include -I$(MOLIB_UPDATER_DIR)/usr/include -I$(tang_DIR)/usr/include -I$(tang_UPDATER_DIR)/usr/include
# 编译选项说明:
# -fPIC: 生成位置无关代码
# -Wall: 开启所有警告
# -Werror: 将警告视为错误
# -g: 包含调试信息
# -O2: 优化级别2
# -I: 头文件搜索路径
CFLAGS += -rdynamic -fasynchronous-unwind-tables # 支持动态链接和异步栈展开
# 链接选项
LDFLAGS = -g -lpthread -lstdc++ -L$(MOLIB_DIR)/usr/lib -L$(MOLIB_UPDATER_DIR)/usr/lib -L$(tang_DIR)/usr/lib -L$(tang_UPDATER_DIR)/usr/lib
# 链接选项说明:
# -g: 包含调试信息
# -lpthread: 链接pthread线程库
# -lstdc++: 链接C++标准库
# -L: 库文件搜索路径
LDFLAGS += -Wl,-rpath-link,$(MOLIB_DIR)/usr/lib:$(MOLIB_UPDATER_DIR)/usr/lib:$(tang_DIR)/usr/lib # 运行时库搜索路径
# 基础依赖库(适配RK3568 Linux环境)
LDFLAGS += -levent -lpower -lwifi -lvolume -ltips -lsharememory -lini -lutils -lpthread -lplayer -ljson-c -lm -lresample -lnvrw -lupdater -lmusiclist -llinklist -lasound -llocalstream
# 库说明:
# -levent: libevent事件驱动库
# -lpower: 电源管理库
# -lwifi: WiFi功能库
# -lvolume: 音量控制库
# -ltips: 提示功能库
# -lsharememory: 共享内存库
# -lini: INI配置文件解析库
# -lutils: 工具函数库
# -lplayer: 播放器核心库
# -ljson-c: JSON解析库
# -lm: 数学库
# -lresample: 音频重采样库
# -lnvrw: NVR读写库
# -lupdater: 系统更新库
# -lmusiclist: 音乐列表库
# -llinklist: 链表库
# -lasound: ALSA音频库
# -llocalstream: 本地流媒体库
# 添加云音乐模块
SRCS += modules/tang_module_cloud_music.c
# 根据歌曲供应商选择相应模块
ifeq ("$(SONG_SUPPLYER)","aispeech") # 思必驰歌曲供应商
SRCS += modules/song_supplyer/speech.c
endif
ifeq ("$(SONG_SUPPLYER)","ximalaya") # 喜马拉雅歌曲供应商
SRCS += modules/song_supplyer/ximalaya.c
LDFLAGS += -lximalaya # 链接喜马拉雅SDK
endif
ifeq ("$(SONG_SUPPLYER)","jushang") # 炬尚歌曲供应商
SRCS += modules/song_supplyer/jushang.c
LDFLAGS += -lvr_jushang # 链接炬尚语音识别SDK
endif
# 本地播放器功能条件编译
ifeq ($(LOCALPLAYER),1) # 如果启用本地播放器
SRCS += modules/tang_module_local_music.c # 添加本地音乐模块
LDFLAGS += -llocalplayer # 链接本地播放器库
else
$(warning localplayer func CLOSED!!!!) # 警告:本地播放器功能关闭
endif
# 数字媒体渲染器功能条件编译
ifeq ($(DMR),1) # 如果启用DMR功能
CFLAGS += -I$(MOLIB_DIR)/usr/include/upnp # 添加UPnP头文件路径
LDFLAGS += -lrender # 链接渲染器库
SRCS += modules/tang_module_dmr.c # 添加DMR模块
else
$(warning dmr func CLOSED!!!!) # 警告:DMR功能关闭
endif
# 多房间音频功能条件编译
ifeq ($(MULROOM),1) # 如果启用多房间音频
SRCS += modules/tang_module_mulroom.c # 添加多房间模块
LDFLAGS += -lmulroom # 链接多房间音频库
else
$(warning multiroom func CLOSED!!!!) # 警告:多房间功能关闭
endif
# 摄像头功能条件编译(RK3568支持MIPI摄像头)
ifeq ($(CAMERA),1) # 如果启用摄像头功能
SRCS += modules/camera/camera.c \ # 添加摄像头相关源文件
modules/camera/lcd.c\
modules/camera/video.c\
modules/camera/savebmp.c\
modules/camera/convert.c\
modules/tang_module_camera.c
# RK3568可能需要添加特定的摄像头库
LDFLAGS += -lv4l2 -lrockchip_mpp # 添加V4L2和Rockchip媒体处理库
else
$(warning camera func CLOSED!!!!) # 警告:摄像头功能关闭
endif
# TTS引擎选择条件编译
ifeq ("$(TTS)","baidu") # 百度TTS引擎
SRCS += misc/tts_baidu.c # 添加百度TTS实现
else
ifeq ("$(TTS)","jietong") # 捷通TTS引擎
LDFLAGS += -lhci_sys -lhci_curl -lhci_tts -ltts_jietong # 链接捷通TTS相关库
else
ifeq ("$(TTS)","aispeech") # 思必驰TTS引擎
LDFLAGS += -lvr # 链接思必驰语音库
endif
endif
endif
# AirPlay功能条件编译
ifeq ($(AIRPLAY),1) # 如果启用AirPlay
SRCS += modules/tang_module_airplay.c # 添加AirPlay模块
else
$(warning airplay func CLOSED!!!!) # 警告:AirPlay功能关闭
endif
# 蓝牙功能条件编译(RK3568通常使用Realtek或Broadcom蓝牙)
ifeq ($(BT),0) # 如果蓝牙功能关闭
$(warning bt func are CLOSED!!!!) # 警告:蓝牙功能关闭
else
SRCS += modules/tang_module_bt.c # 添加蓝牙模块
endif
ifeq ("$(call substring,$(BT),1,3)", "rtk") # Realtek蓝牙模块(RK3568常用)
LDFLAGS += -lrtk_btcore -lbtstack # 链接Realtek蓝牙核心库
endif
ifeq ("$(call substring,$(BT),1,3)", "bcm") # Broadcom蓝牙模块
LDFLAGS += -lbsa -lbt -lappcommon -lchannels -lrecord # 链接Broadcom蓝牙库
endif
# 播放器功能条件编译(适配RK3568硬件解码)
ifeq ($(INGENICPLAYER),1) # 如果启用硬件播放器
SRCS += ingenicplayer/appserver.c ingenicplayer/ingenicplayer.c ingenicplayer/device.c # 添加播放器源文件
LDFLAGS += -lappserver -lrockchip_mpp -lrga # 链接应用服务器和Rockchip媒体处理库
else
$(warning ingenicplayer func CLOSED!!!!) # 警告:硬件播放器功能关闭
endif
# 语音识别功能条件编译
ifeq ("$(VR)","0") # 如果语音识别功能关闭
$(warning vr func are CLOSED!!!!) # 警告:语音识别功能关闭
else
SRCS += modules/tang_module_vr.c # 添加语音识别模块
endif
ifeq ("$(VR)","aispeech") # 思必驰语音识别
LDFLAGS += -lvr # 链接思必驰语音库
endif
ifeq ("$(VR)","iflytek") # 科大讯飞语音识别
LDFLAGS += -lvr_iflytek # 链接科大讯飞语音库
endif
ifeq ("$(VR)","jietong") # 捷通语音识别
LDFLAGS += -lvr_jietong -lrecord -lwakeup_jietong # 链接捷通语音识别和唤醒库
endif
# UI功能条件编译(RK3568支持多种显示接口)
ifeq ("$(UI)","0") # 如果UI功能关闭
$(warning ui func are CLOSED!!!!) # 警告:UI功能关闭
else
SRCS += tang_ui.c # 添加UI模块
endif
ifeq ("$(UI)","lcd") # LCD UI
LDFLAGS += -llcd -llcdshow -lpng -lz -ldrm -lrockchip_drm # 链接LCD显示、PNG和DRM库
endif
ifeq ("$(UI)","smartui") # 智能UI
LDFLAGS += -lsmartui # 链接智能UI库
endif
ifeq ("$(UI)","wayland") # Wayland UI(RK3568常用)
LDFLAGS += -lwayland-client -lwayland-egl # 链接Wayland客户端库
endif
# 闹钟功能条件编译
ifeq ($(ALARM),1) # 如果启用闹钟功能
LDFLAGS += -lalarm # 链接闹钟库
else
$(warning alarm func CLOSED!!!!) # 警告:闹钟功能关闭
endif
# WebRTC功能条件编译
ifeq ($(WEBRTC),1) # 如果启用WebRTC
LDFLAGS += -lwebrtc_audio_processing -lwebrtc # 链接WebRTC音频处理库
else
$(warning webrtc func CLOSED!!!!) # 警告:WebRTC功能关闭
endif
# 设备管理服务功能条件编译
ifeq ($(DMS),1) # 如果启用DMS
SRCS += misc/dms.c # 添加设备管理服务模块
else
$(warning dms func CLOSED!!!!) # 警告:DMS功能关闭
endif
# 胶囊控制功能条件编译
ifeq ($(LAPSULE),1) # 如果启用胶囊控制
SRCS += misc/lapsule_control.c # 添加胶囊控制模块
else
$(warning lapsule func CLOSED!!!!) # 警告:胶囊控制功能关闭
endif
# RK3568特定优化选项
CFLAGS += -march=armv8-a+crc -mtune=cortex-a55 # ARM64架构优化
LDFLAGS += -Wl,--hash-style=gnu # 使用GNU哈希风格
# 目标文件生成规则:将所有的.c文件转换为.c.o文件
OBJS = $(patsubst %.c, %.c.o, $(SRCS))
# 最终目标文件名
TARGET = tang
# 默认目标
all:$(TARGET)
# 链接目标:将所有的.o文件链接成可执行文件
$(TARGET):$(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
# 模式规则:将.c文件编译为.o文件
%.c.o:%.c
$(CC) $(CFLAGS) -c $^ -o $@
# 安装目标
install:
$(INSTALL) -d $(DESTDIR)$(SBINDIR) # 创建sbin目录
$(INSTALL) -d $(DESTDIR)$(INITDIR) # 创建init.d目录
if [ -e $(TARGET) ]; then \ # 如果目标文件存在
$(INSTALL) -m 755 -s --strip-program=$(STRIP) $(TARGET) $(DESTDIR)$(SBINDIR)/; \ # 安装并strip可执行文件
$(INSTALL) -m 755 S10tang.sh $(DESTDIR)$(INITDIR)/; \ # 安装启动脚本
fi
# 清理目标
clean:
-rm -rf $(OBJS) $(TARGET) # 删除所有目标文件和可执行文件
# 卸载目标
uninstall:
if [ -e $(DESTDIR)$(SBINDIR)/$(TARGET) ]; then \ # 如果已安装的目标文件存在
rm -rf $(DESTDIR)$(SBINDIR)/$(TARGET); \ # 删除可执行文件
rm -rf $(DESTDIR)$(INITDIR)/S10tang.sh; \ # 删除启动脚本
fi
# 声明伪目标
.PHONY:all clean install uninstall $(TARGET)
主要源码框架:
tang.c
#include <string.h> // 性能:字符串操作,内存拷贝可能成为瓶颈
#include <stdlib.h> // 架构特点:标准库基础,内存管理和程序控制
#include <signal.h> // 软件设计模式:观察者模式 - 信号处理机制
#include <stdbool.h> // 可读性:布尔类型支持,提高代码表达力
#include <unistd.h> // 性能:系统调用封装,进程控制
#include <pthread.h> // 软件设计模式:主动对象模式 - 多线程支持
#include <errno.h> // 架构特点:错误处理基础
#include <time.h> // 性能:时间相关操作
#include <sys/types.h> // 架构特点:系统类型定义
#include <pwd.h> // 可读性:用户信息获取,可能用于权限控制
#include <sys/stat.h> // 性能:文件状态检查
#include <linux/input.h> // 软件设计模式:事件驱动模式 - 输入事件处理
#include <fcntl.h> // 性能:文件控制,非阻塞IO可能
#include <execinfo.h> // 架构特点:调试支持,堆栈跟踪
// 软件设计模式:外观模式 - 统一的模块接口头文件
#include "event_interface.h" // 事件管理接口
#include "wifi_interface.h" // 网络功能
#include "volume_interface.h" // 音频控制
#include "player_interface.h" // 媒体播放
#include "tips_interface.h" // 用户提示
#include "json-c/json.h" // 性能:JSON解析,可能影响启动速度
#include "utils_interface.h" // 工具函数
#include "power_interface.h" // 电源管理
#include "sharememory_interface.h" // 软件设计模式:共享内存模式 - 进程间通信
#include "ini_interface.h" // 配置管理
#include "nvrw_interface.h" // 非易失存储
#include "updater_interface.h" // 更新功能
#include "localplayer_interface.h" // 本地播放
// 架构特点:应用专用头文件,分层设计
#include "tang_config.h" // 配置定义
#include "lapsule_control.h" // 胶囊控制(特定硬件功能)
#include "battery_capacity.h" // 电池管理
#include "ingenicplayer.h" // 播放器
// 核心应用模块
#include "tang_app.h" // 主应用逻辑
#include "tang_ui.h" // 用户界面
#include "tang_musicplayer.h" // 音乐播放
#include "tang_key_function.h" // 按键功能
#include "tang_tts.h" // 文本转语音
#ifdef SUPPORT_BT
#include "modules/tang_module_bt.h" // 软件设计模式:条件编译模块 - 蓝牙功能
#endif
#ifdef SUPPORT_VR
#include "modules/tang_module_vr.h" // VR功能
#include "vr_interface.h" // VR接口
#endif
#if (SUPPORT_MULROOM == 1)
#include "mulroom_interface.h" // 多房间音频
#include "modules/tang_module_mulroom.h" // 多房间模块
#endif /* SUPPORT_MULROOM == 1 */
// 软件设计模式:模块化设计 - 功能模块分离
#include "modules/tang_module_linein.h" // 线路输入
#include "modules/tang_module_local_music.h" // 本地音乐
#if (SUPPORT_ALARM == 1)
#include "alarm_interface.h" // 闹钟功能
#endif
// 软件设计模式:单例模式 - 全局事件处理器
event_handler *keyevent_handler = NULL; // 按键事件处理器
event_handler *miscevent_handler = NULL; // 杂项事件处理器
char *app_name = NULL; // 应用名称
int tfcard_status = -1; // TF卡状态,性能:存储检测
static int null_cnt = 0; // 空计数,架构特点:状态跟踪
#if (SUPPORT_MULROOM == 1)
#define MULROOM_INFO_PATH "/usr/data/mulroom.json" // 架构特点:配置文件路径
static enum mul_state mulroom_state = MUL_IDLE; // 多房间状态机
#endif /* SUPPORT_MULROOM == 1 */
#if (SUPPORT_BT == BT_BCM)
// 软件设计模式:配置常量模式 - 蓝牙音量参数
#define APP_HS_CALL_VOLUME_MAX 15 // 耳机通话最大音量
#define APP_AVK_VOLUME_MAX 17 // AVK音频最大音量
int bsa_ble_start_regular_enable = 0; // BLE启动标志
int bsa_start_regular_enable = 0; // BSA启动标志
int ble_hh_add_dev_enable = 0; // BLE设备添加标志
int bt_link_state = BT_LINK_DISCONNECTED; // 蓝牙连接状态机
pthread_t bt_reconnect_pthread; // 性能:蓝牙重连线程
pthread_t bt_ring_pthread; // 蓝牙铃声线程
int bt_reconnect_num = 0; // 重连次数
bool bt_ring_flag; // 铃声标志
int disc_num = -1; // 发现设备数量
pthread_mutex_t bt_reconnect_lock; // 软件设计模式:保护性暂停模式 - 线程同步
// 性能:音量映射表,避免运行时计算
static UINT8 avk_volume_set_dsp[APP_AVK_VOLUME_MAX] = {0, 6, 12, 18, 25, 31, 37, 43, 50, 56, 62, 68, 75, 81, 87, 93, 100};
static UINT8 avk_volume_set_phone[APP_AVK_VOLUME_MAX] = {0, 7, 15, 23, 31, 39, 47, 55, 63, 71, 79, 87, 95, 103, 111, 119, 127};
// 软件设计模式:状态模式 - 蓝牙调试状态
enum {
DG_IDLE,
DG_CONNECTED,
DG_CONNECT_FAILED,
DG_DISCONNECTED,
};
int bt_dg_flag = DG_IDLE; // 蓝牙调试状态
#if (SUPPORT_BSA_A2DP_SOURCE == 1)
int bt_av_link_state = BT_LINK_DISCONNECTED; // A2DP源状态
extern int avk_source_set_audio_output(char *ao_iface); // 音频输出设置
#endif /* SUPPORT_BSA_A2DP_SOURCE */
#if (SUPPORT_BSA_PBC == 1)
// 软件设计模式:数据字典模式 - 电话簿路径定义
enum {
TEL_ICH_PATH, /* Path to local incoming calls history object */
TEL_OCH_PATH, /* Path to local outgoing calls history object */
TEL_MCH_PATH, /* Path to local missed calls history object */
TEL_CCH_PATH, /* Path to local combined calls history object */
TEL_PB_PATH, /* Path to local main phone book object */
SIM1_TEL_ICH_PATH, /* Path to SIM Card incoming calls history object */
SIM1_TEL_OCH_PATH, /* Path to SIM Card outgoing calls history object */
SIM1_TEL_MCH_PATH, /* Path to SIM Card missed calls history object */
SIM1_TEL_CCH_PATH, /* Path to SIM Card combined calls history object */
SIM1_TEL_PB_PATH, /* Path to SIM Card main phone book object */
};
// 可读性:清晰的路径映射,便于维护
static char *tel_str[] = {
[TEL_ICH_PATH] = "telecom/ich.vcf", [TEL_OCH_PATH] = "telecom/och.vcf",
[TEL_MCH_PATH] = "telecom/mch.vcf", [TEL_CCH_PATH] = "telecom/cch.vcf",
[TEL_PB_PATH] = "telecom/pb.vcf", [SIM1_TEL_ICH_PATH] = "SIM1/telecom/ich.vcf",
[SIM1_TEL_OCH_PATH] = "SIM1/telecom/och.vcf", [SIM1_TEL_MCH_PATH] = "SIM1/telecom/mch.vcf",
[SIM1_TEL_CCH_PATH] = "SIM1/telecom/cch.vcf", [SIM1_TEL_PB_PATH] = "SIM1/telecom/pb.vcf",
};
#endif /* SUPPORT_BSA_PBC */
#endif /* SUPPORT_BT */
// 软件设计模式:查找表模式 - 信号号到字符串映射
// 性能:数组查找O(1),比switch更高效
static char *signal_str[] = {
[1] = "SIGHUP", [2] = "SIGINT", [3] = "SIGQUIT", [4] = "SIGILL", [5] = "SIGTRAP",
[6] = "SIGABRT", [7] = "SIGBUS", [8] = "SIGFPE", [9] = "SIGKILL", [10] = "SIGUSR1",
[11] = "SIGSEGV", [12] = "SIGUSR2", [13] = "SIGPIPE", [14] = "SIGALRM", [15] = "SIGTERM",
[16] = "SIGSTKFLT", [17] = "SIGCHLD", [18] = "SIGCONT", [19] = "SIGSTOP", [20] = "SIGTSTP",
[21] = "SIGTTIN", [22] = "SIGTTOU", [23] = "SIGURG", [24] = "SIGXCPU", [25] = "SIGXFSZ",
[26] = "SIGVTALRM", [27] = "SIGPROF", [28] = "SIGWINCH", [29] = "SIGIO", [30] = "SIGPWR",
[31] = "SIGSYS", [34] = "SIGRTMIN", [35] = "SIGRTMIN+1", [36] = "SIGRTMIN+2", [37] = "SIGRTMIN+3",
[38] = "SIGRTMIN+4", [39] = "SIGRTMIN+5", [40] = "SIGRTMIN+6", [41] = "SIGRTMIN+7", [42] = "SIGRTMIN+8",
[43] = "SIGRTMIN+9", [44] = "SIGRTMIN+10", [45] = "SIGRTMIN+11", [46] = "SIGRTMIN+12", [47] = "SIGRTMIN+13",
[48] = "SIGRTMIN+14", [49] = "SIGRTMIN+15", [50] = "SIGRTMAX-14", [51] = "SIGRTMAX-13", [52] = "SIGRTMAX-12",
[53] = "SIGRTMAX-11", [54] = "SIGRTMAX-10", [55] = "SIGRTMAX-9", [56] = "SIGRTMAX-8", [57] = "SIGRTMAX-7",
[58] = "SIGRTMAX-6", [59] = "SIGRTMAX-5", [60] = "SIGRTMAX-4", [61] = "SIGRTMAX-3", [62] = "SIGRTMAX-2",
[63] = "SIGRTMAX-1", [64] = "SIGRTMAX",
};
// 软件设计模式:帮助命令模式 - 统一的命令行接口
// 可读性:清晰的帮助信息格式
static void usage(const char *app_name)
{
printf("%s [-bsh] \n"
" -h help (show this usage text)\n"
" -s/-S TODO\n"
" -b/-B run a daemon in the background\n", app_name);
return;
}
char buf[16] = {}; // 性能:静态缓冲区,避免重复分配
// 软件设计模式:错误处理模式 - 统一的信号处理函数
// 性能:崩溃时资源清理,避免资源泄漏
void sig_handler(int signo)
{
char cmd[64] = {};
void *array[10];
int size = 0;
char **strings = NULL;
int i = 0;
// 可读性:详细的错误信息输出
printf("\n\n[%s: %d] tang crashed by signal %s.\n", __func__, __LINE__, signal_str[signo]);
// 架构特点:堆栈跟踪支持,便于调试
printf("Call Trace:\n");
size = backtrace(array, 10);
strings = backtrace_symbols(array, size);
if (strings)
{
for (i = 0; i < size; i++)
{
printf (" %s\n", strings[i]);
}
free (strings); // 性能:及时释放堆栈字符串
}
else
{
printf("Not Found\n\n");
}
// 软件设计模式:条件诊断模式 - 针对特定信号额外诊断
if (signo == SIGSEGV || signo == SIGBUS ||
signo == SIGTRAP || signo == SIGABRT)
{
sprintf(cmd, "cat /proc/%d/maps", getpid());
printf("Process maps:\n");
system(cmd); // 性能:系统调用开销,但崩溃时可接受
}
// 软件设计模式:资源清理模式 - 有序关闭所有服务
printf("stop all services\n");
stopall(-1);
printf("unregister event manager\n");
tang_event_handler_put(keyevent_handler);
tang_event_handler_put(miscevent_handler);
printf("unregister network manager\n");
unregister_from_networkmanager();
#if (SUPPORT_ALARM == 1)
printf("unregister alarm manager\n");
unregister_to_alarm_manager();
#endif
// 架构特点:共享内存清理,避免残留
share_mem_clear();
share_mem_destory();
exit(-1); // 性能:立即退出,避免进一步损坏
}
#ifdef SUPPORT_VR
#if (SUPPORT_VR_WAKEUP == VR_WAKEUP_KEY_LONGPRESS)
// 软件设计模式:状态标志模式 - VR唤醒控制
int vr_flag = 0;
// 软件设计模式:异步任务模式 - VR长按键处理线程
// 性能:后台线程处理,不阻塞主流程
void *vr_longbutton_func(void *arg)
{
vr_flag = 1;
tang_vr_wakeup(); // VR唤醒功能
vr_flag = 0;
return NULL; // make compile happy. 可读性:明确的返回值说明
}
// 软件设计模式:工厂方法模式 - 创建特定功能的线程
// 代码可拓展性:通过条件编译支持不同VR唤醒方式,易于添加新的唤醒模式
// 运行性能:使用线程分离(detach)避免资源泄漏,减少线程管理开销
int create_vr_longbutton_pthread()
{
int ret = 0;
pthread_t vr_longbutton_thread = 0;
// 架构优势:状态检查避免重复创建线程,防止资源竞争
// 代码可读性:清晰的条件判断,防止重复启动
if(vr_flag == 0)
{
ret = pthread_create(&vr_longbutton_thread, NULL, vr_longbutton_func, NULL);
if(ret != 0)
{
// 错误处理完善,提供详细的错误信息
printf ("Create iflytek pthread failed: %s!\n", strerror(errno));
return ret;
}
// 运行性能:分离线程,系统自动回收资源,避免僵尸线程
pthread_detach(vr_longbutton_thread);
}
return ret;
}
#endif
#endif
// 软件设计模式:状态标志模式 - 使用布尔标志管理WiFi配置状态
// 代码可读性:变量命名清晰,明确表示WiFi配置状态
bool wifi_configing = false;
pthread_t wifi_config_pthread;
// 架构优势:使用静态初始化的互斥锁,避免动态初始化开销和竞争条件
pthread_mutex_t wifi_config_lock = PTHREAD_MUTEX_INITIALIZER;
// 软件设计模式:命令模式 - 将WiFi配置操作封装为可执行单元
// 运行性能:线程可取消,避免长时间阻塞,提高系统响应性
void *wifi_config_func(void *args)
{
// 架构优势:设置线程取消状态,支持优雅的线程终止
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
// 状态管理:设置配置状态,防止重复进入配置模式
wifi_configing = true;
// 代码可拓展性:模块化停止操作,便于扩展其他模块
tang_module_stop();
stopall(1);
tang_config_wifi();
// 状态清理:重置状态标志,允许后续操作
wifi_configing = false;
return NULL; // make compile happy. // 代码可读性:明确的返回值说明
}
// 软件设计模式:线程池模式 - 管理WiFi配置线程的生命周期
// 架构优势:互斥锁保护,防止多线程竞争条件
int create_wifi_config_pthread(void)
{
pthread_mutex_lock(&wifi_config_lock);
// 代码可拓展性:支持取消前一个线程,避免资源泄漏
// cancle previous thread.
if (wifi_configing)
{
pthread_cancel(wifi_config_pthread);
}
// 运行性能:创建分离线程,系统自动管理资源
// enter wifi config mode.
if (pthread_create(&wifi_config_pthread, NULL, wifi_config_func, NULL) == -1)
{
// 错误处理:详细的错误信息和资源清理
printf("Create wifi config pthread failed: %s.\n", strerror(errno));
pthread_mutex_unlock(&wifi_config_lock);
return -1;
}
pthread_detach(wifi_config_pthread);
pthread_mutex_unlock(&wifi_config_lock);
return 0;
}
// 软件设计模式:模板方法模式 - WiFi切换与配置使用相似的模式
// 代码可读性:清晰的变量命名,与配置功能对应
bool wifi_switching = false;
pthread_t wifi_switch_pthread;
pthread_mutex_t wifi_switch_lock = PTHREAD_MUTEX_INITIALIZER;
// 架构优势:函数结构一致,便于维护和理解
void *wifi_switch_func(void *args)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
wifi_switching = true;
// 代码可拓展性:统一的模块停止接口,支持功能扩展
tang_module_stop();
stopall(1);
tang_wifi_mode();
wifi_switching = false;
return NULL; // make compile happy.
}
// 软件设计模式:代码复用模式 - 与配置线程创建逻辑高度一致
int create_wifi_switch_pthread(void)
{
pthread_mutex_lock(&wifi_switch_lock);
// cancle previous thread.
if (wifi_switching)
{
pthread_cancel(wifi_switch_pthread);
}
// enter wifi switch mode.
if (pthread_create(&wifi_switch_pthread, NULL, wifi_switch_func, NULL) == -1)
{
printf("Create wifi switch pthread failed: %s.\n", strerror(errno));
pthread_mutex_unlock(&wifi_switch_lock);
return -1;
}
pthread_detach(wifi_switch_pthread);
pthread_mutex_unlock(&wifi_switch_lock);
return 0;
}
#if (SUPPORT_LOCALPLAYER == 1)
// 软件设计模式:回调模式 - TF卡扫描完成的事件通知
// 代码可拓展性:条件编译支持功能可选,便于产品定制
void tfcard_scan_1music_callback(void)
{
#if 0
// 架构优势:状态管理,跟踪TF卡状态
tfcard_status = 1;
// 运行性能:异步启动本地音乐模块,不阻塞扫描过程
tang_module_local_music_startup();
#endif
}
// 软件设计模式:观察者模式 - 扫描完成通知订阅者
// 代码可读性:清晰的函数命名,明确表示扫描完成
void tfcard_scan_done_callback(char *musiclist)
{
#if 1
/* TODO; musicplayer add queue */
// 架构优势:状态更新与模块启动分离,提高可测试性
tfcard_status = 1;
tang_module_local_music_startup();
#endif
}
#endif /* SUPPORT_LOCALPLAYER */
// 软件设计模式:策略模式 - 根据蓝牙状态执行不同操作
// 运行性能:状态检查避免不必要的操作
static void key_bluetooth_handler(void)
{
#if (SUPPORT_BT == BT_BCM)
int state = 0;
// 架构优势:统一的状态获取接口,便于维护
state = tang_bluetooth_hs_get_call_state();
if (state == CALLSETUP_STATE_INCOMMING_CALL)
{
// 代码可读性:清晰的日志输出,便于调试
printf(">>>>>>>>>>>>>answer call>>>>>\n");
tang_bluetooth_hs_answer_call();
}
else if (state == CALL_STATE_LEAST_ONE_CALL_ONGOING ||
state == CALLSETUP_STATE_OUTGOING_CALL ||
state == CALLSETUP_STATE_REMOTE_BEING_ALERTED_IN_OUTGOING_CALL ||
state == CALLHELD_STATE_NO_CALL_HELD)
{
printf(">>>>>>>>>>>>>hang up>>>>>\n");
tang_bluetooth_hs_hangup_call();
}
else if (state == CALLSETUP_STATE_WAITING_CALL)
{
/* you can do other operation */
// 代码可拓展性:预留扩展点,支持更多操作
tang_bluetooth_hs_hold_call(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
}
else if (state == CALLHELD_STATE_PLACED_ON_HOLD_OR_SWAPPED)
{
/* you can do other operation */
tang_bluetooth_hs_hold_call(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
}
else
{
// 错误处理:不支持状态的明确提示
printf("not support state : %d\n", state);
}
#endif
}
#if (SUPPORT_BT == BT_BCM)
// 软件设计模式:自动重试模式 - 实现蓝牙自动重连机制
// 运行性能:互斥锁保护共享资源,避免竞争条件
static void *bt_auto_reconnect_pthread(void *args)
{
/* auto reconnect time:
* 10 minute */
int ret = 0;
// 架构优势:互斥锁保护重连逻辑,确保线程安全
pthread_mutex_lock(&bt_reconnect_lock);
bt_reconnect_num = 10;
// 代码可读性:清晰的重试循环,最大重试次数控制
while (bt_reconnect_num > 0)
{
// 运行性能:状态检查避免不必要的重连尝试
if (BT_LINK_DISCONNECTING == tang_bluetooth_get_link_status() ||
BT_LINK_CONNECTING == tang_bluetooth_get_link_status() ||
BT_LINK_DISCONNECTED == tang_bluetooth_get_link_status())
{
printf("bt_auto_reconnect_pthread start!\n");
ret = tang_bluetooth_auto_reconnect(USE_HS_AVK, 0);
printf("ret = %d\n", ret);
if (ret == 0)
{
printf("reconnect successful!\n");
bt_reconnect_num = 0;
}
else if (ret == -1)
{
// 重试机制:失败时递减重试计数
printf("reconnect failed, retry!\n");
bt_reconnect_num--;
}
else if (ret == -2)
{
// 错误处理:特定错误码的特殊处理
printf("bt_reconnect_devices.xml not existed, no connected device\n");
bt_reconnect_num = 0;
}
else
{
printf("Not supported this type: %d\n", ret);
}
}
else if (BT_LINK_CONNECTED == tang_bluetooth_get_link_status())
{
// 运行性能:已连接状态立即退出,避免不必要的循环
printf("bt link status == BT_LINK_CONNECTED !\n");
bt_reconnect_num = 0;
}
}
// 资源清理:重置重连状态
bt_reconnect_num = 0;
pthread_mutex_unlock(&bt_reconnect_lock);
printf("return bt_auto_reconnect_pthread !\n");
return NULL;
}
// 软件设计模式:简单工厂模式 - 创建蓝牙重连线程
// 代码可拓展性:易于扩展其他类型的蓝牙管理线程
int bluetooth_create_auto_reconnect_pthread()
{
if (pthread_create(&bt_reconnect_pthread, NULL, bt_auto_reconnect_pthread, NULL) != 0) {
printf("create bt_auto_reconnect_pthread failed !\n");
return -1;
}
// 运行性能:分离线程,自动资源回收
pthread_detach(bt_reconnect_pthread);
return 0;
}
// 软件设计模式:命令模式 - 提供取消重连线程的统一接口
// 运行性能:直接设置标志位,无锁操作,快速响应取消请求
// 可读性:函数命名清晰,明确表示取消蓝牙重连线程
int bluetooth_cancel_auto_reconnect_pthread()
{
bt_reconnect_num = 0; // 架构优势:简单的标志位清零,立即终止重连循环
return 0;
}
// 软件设计模式:工作者线程模式 - 专门处理蓝牙铃声播放
// 运行性能:循环播放铃声,sleep(1)控制播放间隔,避免CPU过度占用
static void *bluetooth_ring_pthread(void *args)
{
bt_ring_flag = true; // 状态管理:设置铃声播放标志
while (bt_ring_flag)
{
// 架构优势:通过标志位控制循环,支持优雅终止
printf("tang_play_key: bluetooth_ring\n");
tang_play_key_sync("bluetooth_ring"); // 运行性能:同步播放,确保铃声完整性
sleep(1); // 性能考虑:1秒间隔平衡响应性和资源消耗
}
return NULL;
}
// 软件设计模式:工厂方法模式 - 创建铃声播放线程
// 可拓展性:统一的线程创建接口,易于扩展其他音频播放线程
int bluetooth_create_ring_pthread()
{
if (pthread_create(&bt_ring_pthread, NULL, bluetooth_ring_pthread, NULL) != 0)
{
printf("create bt_ring_pthread failed !\n"); // 错误处理:创建失败日志
return -1;
}
pthread_detach(bt_ring_pthread); // 资源管理:分离线程,系统自动回收资源
return 0;
}
// 软件设计模式:资源清理模式 - 停止铃声播放并释放资源
// 运行性能:标志位设置立即生效,快速停止铃声循环
int bluetooth_cancel_ring_pthread()
{
printf("bluetooth_cancel_ring_pthread !\n"); // 可读性:清晰的调试日志
bt_ring_flag = false; // 架构优势:原子操作停止循环,无需锁保护
return tang_stop_tone(); // 代码设计:返回停止音调的结果,提供操作反馈
}
#endif
/*******************************************************************************
* long press
*******************************************************************************/
// 软件设计模式:状态机模式 - 定义长按按键的状态转换
// 可读性:枚举命名清晰,完整描述长按按键生命周期
enum key_long_press_state {
KEY_LONG_PRESS_INVALID = 0, // 初始或结束状态
KEY_LONG_PRESS_WAIT, // 等待判断长短按
KEY_LONG_PRESS_CANCEL, // 短按取消长按判断
KEY_LONG_PRESS_DONE, // 长按确认
};
// 软件设计模式:策略模式 + 观察者模式 - 按键信息与处理策略封装
// 架构优势:统一管理所有按键事件,支持动态处理策略
struct input_event_key_info {
char *name; // 可读性:按键名称,便于调试和日志
int key_code; // 硬件抽象:Linux输入事件键值
enum key_long_press_state state; // 状态管理:当前按键状态
pthread_t pthread; // 并发控制:每个按键独立线程
pthread_mutex_t lock; // 线程安全:保护状态变量
pthread_cond_t cond; // 同步机制:线程间通信
int timeout_second; // 配置灵活:可配置的长按超时时间
void (*handler)(bool long_press); // 策略模式:长短按不同处理函数
};
// 软件设计模式:策略实现 - WiFi切换处理策略
// 可拓展性:易于添加新的按键处理逻辑
static void wifi_switch_handler(bool long_press)
{
if (long_press)
{
create_wifi_config_pthread(); // 长按进入配置模式
}
else
{
create_wifi_switch_pthread(); // 短按切换模式
}
}
// 软件设计模式:策略实现 - 音量下降处理策略
// 用户体验:长短按实现不同功能,提高操作效率
static void volume_down_handler(bool long_press)
{
if (long_press)
{
tang_previous_song(); // 长按上一曲
}
else
{
tang_volume_down(); // 短按音量减
}
}
// 软件设计模式:策略实现 - 音量上升处理策略
// 架构优势:统一的处理模式,便于维护
static void volume_up_handler(bool long_press)
{
if (long_press)
{
tang_next_song(); // 长按下一曲
}
else
{
tang_volume_up(); // 短按音量加
}
}
// 软件设计模式:策略实现 - 播放暂停处理策略
// 功能集成:单一按键集成播放控制和蓝牙功能
static void play_pause_handler(bool long_press)
{
if (long_press)
{
key_bluetooth_handler(); // 长按蓝牙控制
}
else
{
tang_play_pause(); // 短按播放暂停
}
}
// 软件设计模式:注册表模式 - 集中管理所有按键配置
// 可拓展性:数组形式便于添加新按键,无需修改核心逻辑
static struct input_event_key_info input_event_key_infos[] = {
{ // WiFi切换按键配置
.name = "wifi_switch_key",
.key_code = KEY_MODE, // 硬件映射:Linux标准键值
.lock = PTHREAD_MUTEX_INITIALIZER, // 性能:静态初始化,避免运行时开销
.cond = PTHREAD_COND_INITIALIZER,
.timeout_second = 1, // 用户体验:1秒长按阈值
.handler = wifi_switch_handler, // 策略绑定:WiFi处理函数
},
{ // 音量加按键配置
.name = "volume_up_key",
.key_code = KEY_VOLUMEUP,
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.timeout_second = 1,
.handler = volume_up_handler, // 策略绑定:音量加处理函数
},
{ // 音量减按键配置
.name = "volume_down_key",
.key_code = KEY_VOLUMEDOWN,
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.timeout_second = 1,
.handler = volume_down_handler, // 策略绑定:音量减处理函数
},
{ // 播放暂停按键配置
.name = "play_pause_key",
.key_code = KEY_PLAYPAUSE,
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.timeout_second = 1,
.handler = play_pause_handler, // 策略绑定:播放控制函数
},
};
// 软件设计模式:状态机处理模式 - 长按按键判断逻辑
// 运行性能:条件变量实现高效等待,避免忙等待
static void *key_long_press_func(void *args)
{
struct timeval now;
struct timespec timeout;
struct input_event_key_info *info = (struct input_event_key_info *)args;
pthread_mutex_lock(&info->lock);
// 状态检查:立即取消情况(快速释放)
if (info->state == KEY_LONG_PRESS_CANCEL)
{
info->state = KEY_LONG_PRESS_INVALID;
printf("%s short press\n", info->name); // 可读性:明确的状态日志
if (info->handler)
info->handler(false); // 策略执行:短按处理
pthread_mutex_unlock(&info->lock);
return NULL;
}
// 超时设置:计算条件变量等待时间
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec + info->timeout_second;
timeout.tv_nsec = now.tv_usec * 1000; // 时间转换:微秒到纳秒
// 运行性能:条件变量定时等待,精确控制长按时间
pthread_cond_timedwait(&info->cond,
&info->lock, &timeout);
// 状态判断:等待期间被取消
if (info->state == KEY_LONG_PRESS_CANCEL)
{
info->state = KEY_LONG_PRESS_INVALID;
printf("%s short press\n", info->name);
if (info->handler)
info->handler(false); // 策略执行:短按处理
pthread_mutex_unlock(&info->lock);
return NULL;
}
// 状态转换:确认长按操作
info->state = KEY_LONG_PRESS_DONE;
printf("%s long press\n", info->name);
if (info->handler)
{
info->handler(true); // 策略执行:长按处理
}
pthread_mutex_unlock(&info->lock);
return NULL;
}
// 软件设计模式:工厂方法模式 - 创建长按检测线程
// 架构优势:统一的长按检测入口,状态检查防止重复创建
static void create_key_long_press_pthread(struct input_event_key_info *info)
{
pthread_mutex_lock(&info->lock);
// 状态验证:防止重复处理同一按键
if (info->state != KEY_LONG_PRESS_INVALID)
{
pthread_mutex_unlock(&info->lock);
return ;
}
info->state = KEY_LONG_PRESS_WAIT; // 状态更新:进入等待判断
pthread_mutex_unlock(&info->lock);
// 线程创建:每个按键独立的长按检测线程
if (pthread_create(&info->pthread, NULL, key_long_press_func, (void *)info) == -1)
{
printf("Create key long press pthread failed: %s.\n", strerror(errno));
return ;
}
pthread_detach(info->pthread); // 资源管理:分离线程自动回收
}
// 软件设计模式:状态转换模式 - 取消长按检测
// 运行性能:条件变量信号立即唤醒等待线程
static void key_long_press_cancel(struct input_event_key_info *info)
{
pthread_mutex_lock(&info->lock);
// 状态处理:根据当前状态执行不同取消逻辑
if (info->state == KEY_LONG_PRESS_DONE)
{
// 长按已完成,直接重置状态
info->state = KEY_LONG_PRESS_INVALID;
}
else if (info->state == KEY_LONG_PRESS_WAIT)
{
// 正在等待,发送取消信号
info->state = KEY_LONG_PRESS_CANCEL;
pthread_cond_signal(&info->cond); // 同步机制:立即唤醒等待线程
}
pthread_mutex_unlock(&info->lock);
}
// 软件设计模式:策略路由模式 - 根据输入事件路由到对应的按键处理器
// 运行性能:线性搜索O(n),但按键数量有限,实际性能可接受
// 可读性:清晰的循环结构,易于理解事件匹配逻辑
static int input_event_handler(struct input_event event)
{
int i;
struct input_event_key_info *info;
// 架构优点:使用编译时计算数组大小,避免硬编码
// 可拓展性:新增按键只需在数组中添加,无需修改此函数
for (i = 0; i < sizeof(input_event_key_infos) / sizeof(struct input_event_key_info); i++)
{
info = &input_event_key_infos[i];
// 事件匹配:根据键值匹配预定义的按键配置
if (event.code == info->key_code)
{
// 状态机驱动:按键按下启动长按检测,释放取消检测
if (event.value == 1)
{
create_key_long_press_pthread(info); // 按下:开始长按检测
}
else
{
key_long_press_cancel(info); // 释放:取消长按检测
}
return 0; // 性能优化:匹配成功立即返回
}
}
return -1; // 未匹配的按键事件
}
// 软件设计模式:观察者模式 - 事件回调函数,响应系统事件
// 架构优点:统一的事件处理入口,模块化设计
void keyevent_callback(tang_event event, void *param)
{
// 软件设计模式:状态模式 - 根据事件类型分支处理
switch (event.type) {
case EVENT_KEY:
// 输入验证:确保是键盘事件,提高代码健壮性
if (event.event.key.key.type != EV_KEY)
{
printf("Only support keyboard now.\n");
break;
}
// 可读性:详细的调试日志,便于问题定位
printf("[DEBUG] key %s %s!!!\n",
keycode_str[event.event.key.key.code], keyvalue_str[event.event.key.key.value]);
#if (SUPPORT_USB_AUDIO == 1)
// 软件设计模式:条件过滤模式 - USB音频模式下的按键过滤
// 架构优点:功能隔离,USB模式下限制部分按键功能
if(tang_usb_audio_is_in() == 1)
{
if (event.event.key.key.code != KEY_POWER
&& event.event.key.key.code != KEY_VOLUMEUP
&& event.event.key.key.code != KEY_VOLUMEDOWN)
{
return; // 性能优化:早期返回避免不必要处理
}
}
#endif
// 软件设计模式:责任链模式 - 先尝试通用长按处理,再处理特殊按键
// 运行性能:通用处理成功则提前返回
if (input_event_handler(event.event.key.key) == 0)
break;
// 按键按下事件处理(非长按按键)
if (event.event.key.key.value == 1) {
// 软件设计模式:命令模式 - 将按键映射到具体操作命令
switch (event.event.key.key.code)
{
case KEY_RECORD:
#ifdef SUPPORT_VR
// 软件设计模式:状态依赖命令 - 根据VR状态执行不同操作
// 可拓展性:支持多种VR唤醒模式的条件编译
#if (SUPPORT_VR_WAKEUP == VR_WAKEUP_KEY_SHORTPRESS || SUPPORT_VR_WAKEUP == VR_WAKEUP_VOICE_KEY_MIX)
// 状态机决策:根据VR当前状态选择相应操作
if (tang_vr_get_status() == VR_AEC) {
printf("AEC mode, wakeup\n");
tang_vr_aec_wakeup(); // AEC模式下的唤醒
} else if (tang_vr_get_status() == VR_ASR) {
printf("ASR mode, interrupt\n");
tang_vr_asr_break(); // ASR模式下的中断
}
#elif (SUPPORT_VR_WAKEUP == VR_WAKEUP_KEY_LONGPRESS)
// 异步处理:创建VR长按线程,避免阻塞主线程
if(create_vr_longbutton_pthread()) { // in case of block.
printf("create_iflytek_pthread failed!\n");
break;
}
#endif
#endif
break;
case KEY_F1:
// 软件设计模式:工厂方法调用 - 创建WiFi配置线程
create_wifi_config_pthread(); // in case of block.
break;
case KEY_BLUETOOTH:
// 直接函数调用:蓝牙按键处理
key_bluetooth_handler();
break;
case KEY_PREVIOUSSONG:
// 命令执行:上一曲操作
tang_previous_song();
break;
case KEY_NEXTSONG:
// 命令执行:下一曲操作
tang_next_song();
break;
case KEY_MENU:
// 命令执行:音源切换
tang_snd_source_switch();
break;
case KEY_F3: /* music music Shortcut key 1 */
// 软件设计模式:参数化命令 - 带参数的快捷操作
tang_music_list(0);
break;
case KEY_F4: /* music music Shortcut key 2 */
tang_music_list(1);
break;
case KEY_F5: /* music music Shortcut key 3 */
tang_music_list(2);
break;
case KEY_POWER:
// 系统命令:关机操作
tang_power_off();
break;
default:
// 架构优点:静默处理未支持按键,避免不必要的日志输出
//printf("UnSupport key down in %s:%s:%d.\n", __FILE__, __func__, __LINE__);
break;
}
} else {
// 按键释放事件处理
// 软件设计模式:有限状态机 - 处理按键释放状态
switch (event.event.key.key.code) {
case KEY_RECORD:
/*TODO: add VR_WAKEUP_KEY_LONGPRESS support*/
// 可拓展性:预留VR长按释放处理接口
break;
default:
// 大多数按键释放不需要特殊处理
break;
}
}
break;
case EVENT_MISC:
default:
// 软件设计模式:默认处理 - 忽略不支持的事件类型
// 架构优点:良好的向前兼容性
break;
}
return;
}
// 软件设计模式:观察者模式 - 处理各种杂项事件的回调函数
// 架构优点:统一的事件处理入口,模块化设计
void miscevent_callback(tang_event event, void *param)
{
// 软件设计模式:状态模式 - 根据事件类型分支处理
switch (event.type) {
case EVENT_MISC:
// 可读性:清晰的事件日志,便于调试
printf("[misc event] %s : %s.\n", event.event.misc.name, event.event.misc.type);
// 软件设计模式:策略模式 - 根据事件名称路由到不同处理逻辑
// Linein事件处理
if (!strcasecmp(event.event.misc.name, "linein")
#if (SUPPORT_MULROOM == 1)
&& mulroom_state != MUL_GROUP_RECEIVER // 架构优点:状态检查,避免冲突
#endif /* SUPPORT_MULROOM == 1 */
) {
if (!strcasecmp(event.event.misc.type, "plugin")) { // linein plugin
// 运行性能:UI更新与硬件操作分离
tang_ui_linein_plugin();
tang_module_stop();
tang_linein_on();
lapsule_do_linein_on(); // 特定硬件操作
} else if (!strcasecmp(event.event.misc.type, "plugout")) { // linein plugout
tang_ui_linein_plugout();
tang_linein_off();
lapsule_do_linein_off();
}
} else if(!strcasecmp(event.event.misc.name, "usb")) {
#if 0
// 架构缺点:注释掉的代码影响可读性,应该移除或使用条件编译
if (!strcasecmp(event.event.misc.type, "connected")) { // usb plugin
system("umount /mnt/sdcard/");
system("echo /dev/mmcblk0p1 > /sys/devices/platform/jz-dwc2/dwc2/gadget/lun0/file");
} else if (!strcasecmp(event.event.misc.type, "disconnected")) { // usb plugout
system("echo 0 > /sys/class/android_usb/android0/enable");
system("mount /dev/mmcblk0p1 /mnt/sdcard/");
}
#endif
#if (SUPPORT_USB_AUDIO == 1)
} else if(!strcasecmp(event.event.misc.name, "uaudio")) {
// 可拓展性:USB音频功能的条件编译支持
if (!strcasecmp(event.event.misc.type, "connected")) {
tang_usb_audio_plug_in();
}else if(!strcasecmp(event.event.misc.type,"disconnected")){
tang_usb_audio_plug_out();
}
#endif
} else if (!strcasecmp(event.event.misc.name, "tfcard")) {
// 软件设计模式:状态检查模式 - 避免重复处理
if (!strcasecmp(event.event.misc.type, "plugin")) { // tfcard plugin
if (tfcard_status != 1) {
tang_ui_localplayer_plugin();
tang_play_key("tf_add");
tfcard_status = 1; // 状态管理:更新TF卡状态
} else {
// do nothing. // 运行性能:避免重复操作
}
} else if (!strcasecmp(event.event.misc.type, "plugout")) { // tfcard plugout
if (tfcard_status != 0) {
tang_ui_localplayer_plugout();
#if (SUPPORT_LOCALPLAYER == 1)
if (snd_source == SND_SRC_LOCALPLAY)
tang_musicplayer_stop(tang_musicplayer_handler); // 条件停止播放器
#endif
tang_play_key("tf_remove");
tfcard_status = 0;
}
}
} else if (!strcasecmp(event.event.misc.name, "headset")) {
// 架构缺点:空实现,应该移除或添加实际功能
if (!strcasecmp(event.event.misc.type, "plugin")) { // headset plugin
printf("headset plugin.\n");
// do nothing.
} else if (!strcasecmp(event.event.misc.type, "plugout")) { // headset plugout
printf("headset plugout.\n");
// do nothing.
}
} else if (!strcasecmp(event.event.misc.name, "spdif")) {
// 类似地,空实现影响代码质量
if (!strcasecmp(event.event.misc.type, "plugin")) { // spdif-out plugin
printf("spdif plugin.\n");
// do nothing.
} else if (!strcasecmp(event.event.misc.type, "plugout")) { // spdif-out plugout
printf("spdif plugout.\n");
// do nothing.
}
} else if (!strcasecmp(event.event.misc.name, "volume")) {
// 软件设计模式:事件日志模式 - 记录但不处理
if (!strcasecmp(event.event.misc.type, "update music")) {
printf("%s volume to %d.\n", event.event.misc.type, event.event.misc.value[0]);
} else if (!strcasecmp(event.event.misc.type, "update bt_music")) {
printf("%s volume to %d.\n", event.event.misc.type, event.event.misc.value[0]);
} else if (!strcasecmp(event.event.misc.type, "update bt_call")) {
printf("%s volume to %d.\n", event.event.misc.type, event.event.misc.value[0]);
} else if (!strcasecmp(event.event.misc.type, "update unknown")) {
printf("%s volume to %d.\n", event.event.misc.type, event.event.misc.value[0]);
} else {
printf("unhandle volume event: %s.\n", event.event.misc.type);
}
#if (SUPPORT_BT == BT_BCM)
} else if (!strcasecmp(event.event.misc.name, "bluetooth")) {
// 软件设计模式:复杂状态机 - 蓝牙连接状态管理
if (!strcasecmp(event.event.misc.type, "connecting")) {
; // do nothing if bluetooth device is connecting.
} else if (!strcasecmp(event.event.misc.type, "disc_new")) {
} else if (!strcasecmp(event.event.misc.type, "disc_complete")) {
bsa_start_regular_enable = 1; // 状态更新:发现完成
} else if (!strcasecmp(event.event.misc.type, "sec_link_down")) {
/*
* Reason code 0x13: Mobile terminate bluetooth connection
* Reason code 0x8: connection timeout(beyond distance)
*/
// 软件设计模式:错误分类处理
UINT8 link_down_data = 0;
link_down_data = tang_bluetooth_get_link_down_status();
if (link_down_data == 0x13) {
printf("Mobile terminate bluetooth connection.\n");
} else if (link_down_data == 0x8) {
printf("BT connection timeout(beyond distance maybe)!\n");
int state = 0;
state = bluetooth_create_auto_reconnect_pthread(); // 自动重连
if (state == 0) {
printf("bluetooth_create_auto_reconnect_pthread success !\n");
} else if (state == -1) {
printf("bluetooth_create_auto_reconnect_pthread failed !\n");
}
} else if (link_down_data == 0x16) {
printf("connection terminated by local host!\n");
} else {
printf("not handle link_down_data %d, Ignore.\n", link_down_data);
}
} else {
printf("unhandle bluetooth event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_hs")) {
// 软件设计模式:事件处理链 - 蓝牙电话事件处理
if (!strcasecmp(event.event.misc.type, "connected")) {
if (tang_bluetooth_get_link_status() == BT_LINK_CONNECTED) {
if (bt_link_state == BT_LINK_DISCONNECTED) {
bt_link_state = BT_LINK_CONNECTED;
tang_ui_bt_connected();
tang_bluetooth_set_visibility(0, 0);
//tang_module_stop();
/* FIXME: do not stop if music playing. will skip tone. */
tang_play_key_sync("bluetooth_connect"); // 同步播放连接音
/* snd_source = SND_SRC_BT_AVK; */
}
#if (SUPPORT_BSA_PBC == 1)
tang_bluetooth_pbc_open_connection(); // 电话本连接
#endif
}
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
bluetooth_cancel_ring_pthread(); // 资源清理:停止铃声
if (tang_bluetooth_get_link_status() == BT_LINK_DISCONNECTED) {
if (bt_link_state == BT_LINK_CONNECTED) {
bt_link_state = BT_LINK_DISCONNECTED;
tang_play_key("bluetooth_disconnect");
tang_bluetooth_set_visibility(1, 1);
tang_ui_bt_disconnected();
}
#if (SUPPORT_BSA_PBC == 1)
tang_bluetooth_pbc_close_connection();
#endif
}
} else if (!strcasecmp(event.event.misc.type, "ring")) {
// 软件设计模式:资源冲突管理 - VR与蓝牙铃声互斥
#ifdef SUPPORT_VR
if (tang_vr_get_status()) {
printf("invoking tang_vr_stop()\n");
tang_vr_stop(); // 停止VR以播放铃声
}
#endif
//TODO: should pause here, resume music after hangup.
if (tang_module_stop()) {
printf("can not ring.\n");
} else {
bluetooth_create_ring_pthread(); // 创建铃声线程
snd_source = SND_SRC_BT_AVK; // 更新音源状态
}
} else if (!strcasecmp(event.event.misc.type, "hangup")) {
bluetooth_cancel_ring_pthread(); // 停止铃声
#ifdef SUPPORT_VR
if(!tang_vr_get_status()) {
printf("invoking tang_vr_start()\n");
tang_vr_start(); // 挂断后重启VR
}
#endif
} else if (!strcasecmp(event.event.misc.type, "call")) {
bluetooth_cancel_ring_pthread();
#ifdef SUPPORT_VR
if (tang_vr_get_status()) {
printf("invoking tang_vr_stop()\n");
tang_vr_stop();
}
#endif
//TODO: should pause here, resume music after hangup.
if (tang_module_stop()) {
share_mem_set(BT_HS_DOMAIN, RESPONSE_CANCEL); // 共享内存通信
} else {
share_mem_set(BT_HS_DOMAIN, RESPONSE_DONE);
snd_source = SND_SRC_BT_AVK;
}
} else if (!strcasecmp(event.event.misc.type, "close")) {
} else if (!strcasecmp(event.event.misc.type, "vgs")) {
// 软件设计模式:数据转换 - 手机音量到设备音量的映射
int volume = event.event.misc.value[0];
tang_volume_set(volume * 100 / APP_HS_CALL_VOLUME_MAX, BT_CALL_VOLUME);
printf("phone volume: %d, tang set hs volume: %d\n",
volume,
volume * 100 / APP_HS_CALL_VOLUME_MAX);
} else {
printf("unhandle bt phone event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_avk")) {
// 软件设计模式:事件镜像 - 与bt_hs类似但独立的处理逻辑
if (!strcasecmp(event.event.misc.type, "connected")) {
if (tang_bluetooth_get_link_status() == BT_LINK_CONNECTED) {
if (bt_link_state == BT_LINK_DISCONNECTED) {
bt_link_state = BT_LINK_CONNECTED;
tang_ui_bt_connected();
tang_bluetooth_set_visibility(0, 0);
//tang_module_stop();
/* FIXME: do not stop if music playing. will skip tone. */
tang_play_key_sync("bluetooth_connect");
}
}
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
if (tang_bluetooth_get_link_status() == BT_LINK_DISCONNECTED) {
if (bt_link_state == BT_LINK_CONNECTED) {
bt_link_state = BT_LINK_DISCONNECTED;
tang_play_key("bluetooth_disconnect");
tang_bluetooth_set_visibility(1, 1);
tang_ui_bt_disconnected();
}
}
} else if (!strcasecmp(event.event.misc.type, "play")) {
if (tang_module_stop()) {
share_mem_set(BT_AVK_DOMAIN, RESPONSE_CANCEL);
} else {
share_mem_set(BT_AVK_DOMAIN, RESPONSE_DONE);
snd_source = SND_SRC_BT_AVK;
}
} else if (!strcasecmp(event.event.misc.type, "pause")) {
printf("bt music player paused(or stopped).\n");
} else if (!strcasecmp(event.event.misc.type, "set_abs_vol")) {
// 软件设计模式:查找表模式 - 音量映射
int index = 0;
int volume = 0;
int fd = 0;
volume = event.event.misc.value[0];
fd = event.event.misc.value[1];
// 逆向查找音量映射
for (index = (APP_AVK_VOLUME_MAX -1); index >= 0; index--) {
if (avk_volume_set_phone[index] <= volume)
break;
}
if (index < 0) {
printf("failed to get music volume %d from avk_volume_set_dsp\n", volume);
break;
}
// 软件设计模式:适配器模式 - 支持不同音频后端
if (AUDIO_OSS == get_audio_type()) {
/* Note: add app_avk_cb.fd judged, because when play tts,
* we reviced ABS_VOL_CMD_EVT, and set volume to dsp,
* it will generate a case of sound mutation */
if (fd != -1) {
tang_volume_set(avk_volume_set_dsp[index], BT_MUSIC_VOLUME);
} else {
// 配置持久化
char vol[8] = {};
sprintf(vol, "%d", avk_volume_set_dsp[index]);
if (tang_ini_setkey("/usr/data/system.ini", "volume", "bt_music", vol)) {
printf("save volume to /usr/data/system.ini error.\n");
break;
}
}
} else if (AUDIO_ALSA == get_audio_type()) {
tang_volume_set(avk_volume_set_dsp[index], BT_MUSIC_VOLUME);
} else {
printf("Not support audio type: %d!!\n", get_audio_type());
}
printf("phone volume: 0x%x, tang set avk volume: %d\n",
volume,
avk_volume_set_dsp[index]);
} else if (!strcasecmp(event.event.misc.type, "get_elem_attr")) {
// 软件设计模式:数据解析模式 - 解析音乐元数据
int i = 0;
int attr_id = 0;
tBSA_AVK_GET_ELEMENT_ATTR_MSG *p_data = NULL;
p_data = tang_bluetooth_avk_get_element_att();
printf("p_data->num_attr = %d\n", p_data->num_attr);
printf("p_data->status = %d\n", p_data->status);
for (i = 0; i < p_data->num_attr; i++) {
attr_id = p_data->attr_entry[i].attr_id;
// 音乐信息分类输出
if (attr_id == AVRC_MEDIA_ATTR_ID_TITLE) {
printf("music Title: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_ARTIST) {
printf("music Artist Name: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_ALBUM) {
printf("music Album Name: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_TRACK_NUM) {
printf("music Track Number: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_NUM_TRACKS) {
printf("music Total Number of Tracks: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_GENRE) {
printf("music Genre: %s\n", p_data->attr_entry[i].name.data);
} else if (attr_id == AVRC_MEDIA_ATTR_ID_PLAYING_TIME) {
printf("music Playing Time: %s\n", p_data->attr_entry[i].name.data);
}
}
} else if (!strcasecmp(event.event.misc.type, "play_status")) {
// 运行性能:获取播放状态信息
tBSA_AVK_GET_PLAY_STATUS_MSG *play_status_msg;
play_status_msg = tang_bluetooth_avk_get_play_status();
printf("play status : %d\n", play_status_msg->play_status);
printf("play song len : %d\n", play_status_msg->song_len);
printf("play song pos : %d\n", play_status_msg->song_pos);
} else {
printf("unhandle bt music event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_av")) {
// A2DP源模式处理
if (!strcasecmp(event.event.misc.type, "open")) {
/* open successful */
if (event.event.misc.value[0] == 0) {
#if (SUPPORT_BSA_A2DP_SOURCE == 1)
bt_av_link_state = BT_LINK_CONNECTED;
char *ao_iface = "stream:sockfile=/var/run/bt-av-stream.socket";
avk_source_set_audio_output(ao_iface); // 设置音频输出接口
#endif
/* open failed */
} else {
#if (SUPPORT_BSA_A2DP_SOURCE == 1)
bt_av_link_state = BT_LINK_CONNECT_FAILED;
#endif
printf("AV open failed!\n");
}
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
#if (SUPPORT_BSA_A2DP_SOURCE == 1)
bt_av_link_state = BT_LINK_DISCONNECTED;
char *ao_iface = "oss:/dev/dsp"; // 回退到默认音频输出
avk_source_set_audio_output(ao_iface);
#endif
} else if (!strcasecmp(event.event.misc.type, "play")) {
} else if (!strcasecmp(event.event.misc.type, "pause")) {
/* REMOTE_CMD_EVT */
} else if (!strcasecmp(event.event.misc.type, "RC")) {
// 软件设计模式:命令分发模式 - 远程控制命令处理
int av_cur_play_state;
switch(event.event.misc.value[0]) {
case BSA_AV_RC_PLAY:
printf("AV RC Play!\n");
av_cur_play_state = tang_bluetooth_av_get_play_state();
switch (av_cur_play_state) {
case APP_AV_PLAY_PAUSED:
tang_bluetooth_av_resume_play();
break;
case APP_AV_PLAY_STOPPED:
break;
case APP_AV_PLAY_STARTED:
/* Already started */
break;
case APP_AV_PLAY_STOPPING:
/* Stop in progress */
break;
default:
printf("Unsupported play state (%d)\n", av_cur_play_state);
break;
}
break;
case BSA_AV_RC_STOP:
printf("AV RC Stop!\n");
tang_bluetooth_av_stop_play();
break;
case BSA_AV_RC_PAUSE:
printf("AV RC Pause!\n");
tang_bluetooth_av_pause_play();
break;
case BSA_AV_RC_FORWARD:
printf("AV RC Forward!\n");
break;
case BSA_AV_RC_BACKWARD:
printf("AV RC Backward!\n");
break;
case BSA_AV_RC_VOL_UP:
printf("AV RC VOl_UP!\n");
break;
case BSA_AV_RC_VOL_DOWN:
printf("AV RC VOl_DOWN!\n");
break;
default:
printf("key: 0x%x", event.event.misc.value[0]);
break;
}
} else if (!strcasecmp(event.event.misc.type, "rc_open")) {
} else if (!strcasecmp(event.event.misc.type, "rc_close")) {
} else {
printf("unhandle bt music event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_ble")) {
// BLE蓝牙低功耗处理
if (!strcasecmp(event.event.misc.type, "disc_new")) {
} else if (!strcasecmp(event.event.misc.type, "disc_complete")) {
bsa_ble_start_regular_enable = 1;
#if (SUPPORT_BSA_BLE_HH == 0)
// 软件设计模式:设备枚举模式 - 遍历发现的BLE设备
int index;
tAPP_DISCOVERY_CB *app_discovery_cb = NULL;
app_discovery_cb = tang_bluetooth_disc_get_device_info();
for (index = 0; index < APP_DISC_NB_DEVICES; index++) {
if (app_discovery_cb->devs[index].in_use != FALSE) {
printf("Dev: %d\n", index);
// 设备信息详细输出
printf("\tBdaddr:%02x:%02x:%02x:%02x:%02x:%02x \n",
app_discovery_cb->devs[index].device.bd_addr[0],
app_discovery_cb->devs[index].device.bd_addr[1],
app_discovery_cb->devs[index].device.bd_addr[2],
app_discovery_cb->devs[index].device.bd_addr[3],
app_discovery_cb->devs[index].device.bd_addr[4],
app_discovery_cb->devs[index].device.bd_addr[5]);
printf("\tName: %s\n", app_discovery_cb->devs[index].device.name);
char *ble_name = (char *)app_discovery_cb->devs[index].device.name;
if (!strcmp(ble_name, "BSA_BLE"))
{
// 特定设备的制造商数据解析
bsa_manu_data manu_data;
int index = 0;
UINT8 * eir_data = app_discovery_cb->devs[index].device.eir_data;
tang_bluetooth_parse_eir_manuf_specific(eir_data, &manu_data);
printf("manu_data.data_length = %d\n", manu_data.data_length);
printf("manu_data.company_id = 0x%02x\n", manu_data.company_id);
printf("manu_data: \n");
for (index = 0; index < manu_data.data_length; index++)
{
printf("%x ", manu_data.p_manu[index]);
}
printf("\n");
}
printf("\tClassOfDevice: %02x:%02x:%02x => %s\n",
app_discovery_cb->devs[index].device.class_of_device[0],
app_discovery_cb->devs[index].device.class_of_device[1],
app_discovery_cb->devs[index].device.class_of_device[2],
tang_bluetooth_get_cod_string(app_discovery_cb->devs[index].device.class_of_device));
printf("\tRssi: %d\n", app_discovery_cb->devs[index].device.rssi);
if (app_discovery_cb->devs[index].device.eir_vid_pid[0].valid) {
printf("\tVidSrc: %d Vid: 0x%04X Pid: 0x%04X Version: 0x%04X",
app_discovery_cb->devs[index].device.eir_vid_pid[0].vendor_id_source,
app_discovery_cb->devs[index].device.eir_vid_pid[0].vendor,
app_discovery_cb->devs[index].device.eir_vid_pid[0].product,
app_discovery_cb->devs[index].device.eir_vid_pid[0].version);
}
}
}
#endif
} else {
printf("unhandle bt ble event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_hh")) {
// 蓝牙HID设备处理
if (!strcasecmp(event.event.misc.type, "add_dev")) {
ble_hh_add_dev_enable = 1;
} else if (!strcasecmp(event.event.misc.type, "connected")) {
} else if (!strcasecmp(event.event.misc.type, "close")) {
} else {
printf("unhandle bt hh event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "bt_avrcp")) {
// AVRCP协议事件处理
if (!strcasecmp(event.event.misc.type, "playing")) {
printf("playing!\n");
} else if (!strcasecmp(event.event.misc.type, "paused")) {
printf("pause!\n");
} else if (!strcasecmp(event.event.misc.type, "stopped")) {
printf("stopped!\n");
} else if (!strcasecmp(event.event.misc.type, "track_change")) {
tang_bluetooth_avk_send_get_element_att_cmd(); // 获取新曲目信息
} else if (!strcasecmp(event.event.misc.type, "play_pos")) {
printf("play_pos: %d\n", event.event.misc.value[0]);
}
} else if (!strcasecmp(event.event.misc.name, "bt_ops")) {
// 对象推送服务处理
if (!strcasecmp(event.event.misc.type, "connected")) {
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
} else if (!strcasecmp(event.event.misc.type, "send_request")) {
char *ops_file_name = NULL;
ops_file_name = tang_bluetooth_ops_get_object_name();
printf("ops_file_name = %s\n", ops_file_name);
printf("len = %d\n", strlen(ops_file_name));
} else if (!strcasecmp(event.event.misc.type, "send_start")) {
} else if (!strcasecmp(event.event.misc.type, "send_end")) {
}
} else if (!strcasecmp(event.event.misc.name, "bt_dg")) {
// 蓝牙调试事件处理
if (!strcasecmp(event.event.misc.type, "open")) {
printf("state: %d\n", event.event.misc.value[0]);
if (event.event.misc.value[0] == 0)
bt_dg_flag = DG_CONNECTED;
else if (event.event.misc.value[0] == 1)
bt_dg_flag = DG_CONNECT_FAILED;
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
bt_dg_flag = DG_DISCONNECTED;
} else if (!strcasecmp(event.event.misc.type, "find_service")) {
}
/* phone book client */
} else if (!strcasecmp(event.event.misc.name, "bt_pbc")) {
// 电话本客户端处理
if (!strcasecmp(event.event.misc.type, "connected")) {
#if (SUPPORT_BSA_PBC == 1)
tang_bluetooth_pbc_get_phonebook(tel_str[TEL_PB_PATH]); // 获取电话本
#endif /* SUPPORT_BSA_PBC */
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
}
#endif /* SUPPORT_BT */
} else if (!strcasecmp(event.event.misc.name, "dlna")) {
// DLNA媒体服务器事件处理
if (!strcasecmp(event.event.misc.type, "connected")) {
; // do nothing on dlna device connected event
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
; // do nothing on dlna device disconnected event
} else if (!strcasecmp(event.event.misc.type, "play")){
if (tang_module_stop())
share_mem_set(RENDER_DOMAIN, RESPONSE_CANCEL);
else
share_mem_set(RENDER_DOMAIN, RESPONSE_DONE);
} else if (!strcasecmp(event.event.misc.type, "pause")){
printf("dlna player paused.\n");
} else if (!strcasecmp(event.event.misc.type, "resume")){
printf("dlna player resume.\n");
} else {
printf("unhandle dlna event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "musicplayer")) {
// 音乐播放器事件处理
if (!strcasecmp(event.event.misc.type, "play")) {
if (tang_module_stop())
share_mem_set(MUSICPLAYER_DOMAIN, RESPONSE_CANCEL);
else
share_mem_set(MUSICPLAYER_DOMAIN, RESPONSE_DONE);
} else if (!strcasecmp(event.event.misc.type, "playing")) {
printf("music player playing.\n");
} else if (!strcasecmp(event.event.misc.type, "pause")) {
printf("music player paused.\n");
} else if (!strcasecmp(event.event.misc.type, "resume")) {
printf("music player resume.\n");
} else {
printf("unhandle music event: %s.\n", event.event.misc.type);
}
} else if (!strcasecmp(event.event.misc.name, "airplay")) {
// AirPlay事件处理
if (!strcasecmp(event.event.misc.type, "connected")) {
if (tang_module_stop())
share_mem_set(AIRPLAY_DOMAIN, RESPONSE_CANCEL);
else
share_mem_set(AIRPLAY_DOMAIN, RESPONSE_DONE);
} else if (!strcasecmp(event.event.misc.type, "disconnected")) {
printf("phone disconnected, airplay play stop.\n");
} else if (!strcasecmp(event.event.misc.type, "paused")) {
printf("airplay play paused.\n");
} else if (!strcasecmp(event.event.misc.type, "resumed")) {
printf("airplay play resumed.\n");
}
} else if (!strcasecmp(event.event.misc.name, "localplayer")) {
// 本地播放器事件处理
if (!strcasecmp(event.event.misc.type, "play")) {
if (tang_module_stop())
share_mem_set(LOCALPLAYER_DOMAIN, RESPONSE_CANCEL);
else
share_mem_set(LOCALPLAYER_DOMAIN, RESPONSE_DONE);
} else if (!strcasecmp(event.event.misc.type, "playing")) {
printf("localplayer playing.\n");
} else if (!strcasecmp(event.event.misc.type,"pause")) {
printf("localplayer paused.\n");
} else if (!strcasecmp(event.event.misc.type,"resume")) {
printf("localplayer resumed.\n");
}
} else if (!strcasecmp(event.event.misc.name,"vr")) {
// VR语音识别事件处理
if (!strcasecmp(event.event.misc.type,"vr wake up"))
tang_ui_asr_wakeup();
else if (!strcasecmp(event.event.misc.type,"vr failed"))
tang_ui_asr_failed();
else if (!strcasecmp(event.event.misc.type,"vr unclear"))
tang_ui_asr_unclear();
#if (SUPPORT_MULROOM == 1)
} else if (!strcasecmp(event.event.misc.name, "multiroom")) {
// 多房间音频事件处理
if (!strcasecmp(event.event.misc.type, "group_dist")) {
printf("group dist event\n");
module_mulroom_audio_change(MR_AO_DISTRIBUTOR); // 切换到分发模式
} else if (!strcasecmp(event.event.misc.type, "dismiss_dist")) {
printf("dismiss dist event\n");
module_mulroom_audio_change(MR_AO_NORMAL); // 回退到普通模式
} else if (!strcasecmp(event.event.misc.type, "group_recv")) {
printf("group recv event\n");
tang_module_stop();
stopall(-1); // 停止所有服务
} else if (!strcasecmp(event.event.misc.type, "dismiss_recv")) {
printf("dismiss recv event\n");
startall(-1); // 启动所有服务
}
#endif /* SUPPORT_MULROOM == 1 */
} else {
// 默认处理:未支持的事件
printf("Unhandle event: %s-%s.\n", event.event.misc.name, event.event.misc.type);
}
break;
case EVENT_KEY:
default:
// 软件设计模式:默认分支 - 忽略不支持的事件类型
break;
}
return;
}
/*
* 架构设计分析:
* 优点:采用事件驱动架构,通过JSON消息进行组件间通信,松耦合设计
* 缺点:函数职责过重,违反了单一职责原则,包含太多不同关注点的处理逻辑
* 设计模式:观察者模式(事件回调)、有限状态机模式(网络状态转换)
*/
// 时间同步线程函数 - 在后台线程中执行时间同步操作
static void *sync_time_func(void *arg)
{
#if (SUPPORT_MULROOM == 1)
// 多房间支持模式:使用专用的NTPD模块
module_mulroom_run_ntpd();
#else
// 单机模式:直接调用系统ntpd命令进行时间同步
// 性能问题:使用system()调用创建新进程,性能开销较大
// 安全性:直接执行shell命令存在安全风险
tang_system("ntpd -nq");
#endif
#if (SUPPORT_ALARM == 1)
// 支持闹钟功能:使用专门的RTC设置接口
tang_alarm_set_rtc_time(time(NULL));
#else
// 不支持闹钟:使用hwclock命令写入硬件时钟
// 可维护性问题:硬编码设备路径"/dev/rtc0",缺乏灵活性
tang_system("hwclock -w -u -f /dev/rtc0");
#endif
return NULL;
}
/*
* 网络事件回调函数 - 处理所有网络相关状态变化
* 软件设计问题:函数过长,违反单一职责原则,应该拆分为多个专门的处理函数
* 性能考虑:JSON解析和字符串比较可能成为性能瓶颈
*/
int network_callback(const char *p)
{
pthread_t sync_time_pthread;
struct json_object *wifi_event = NULL;
char test[64] = {0}; // 临时缓冲区,命名不清晰,用途不明确
wifi_ctl_msg_t new_mode;
event_info_t network_event;
// 日志输出:良好的调试信息
printf("[%s] network event: %s\n", __func__, p);
// JSON解析:使用json-c库解析事件数据
// 错误处理:缺乏对解析失败的检查
wifi_event = json_tokener_parse(p);
//printf("event.to_string()=%s\n", json_object_to_json_string(event));
// 初始化事件结构体
memset(&network_event, 0, sizeof(event_info_t));
// JSON字段提取:重复代码模式,可考虑提取为辅助函数
struct json_object *tmp = NULL;
json_object_object_get_ex(wifi_event, "name", &tmp);
if(tmp != NULL){
// 字符串拷贝:使用strncpy但未确保null终止,存在安全隐患
strncpy(network_event.name, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
//printf("name:%s\n", json_object_get_string(tmp));
}
json_object_object_get_ex(wifi_event, "type", &tmp);
if(tmp != NULL){
strncpy(network_event.type, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
//printf("type:%s\n", json_object_get_string(tmp));
}
json_object_object_get_ex(wifi_event, "content", &tmp);
if(tmp != NULL){
strncpy(network_event.content, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
//printf("content:%s\n", json_object_get_string(tmp));
}
// 初始化WiFi控制消息
memset(&new_mode, 0, sizeof(wifi_ctl_msg_t));
/*
* STA状态事件处理 - 工作站模式状态变化
* 设计模式:有限状态机,处理连接状态转换
*/
if (!strncmp(network_event.type, event_type_str[EVENT_TYPE_STA_STATUS],
strlen(event_type_str[EVENT_TYPE_STA_STATUS]))) {
//printf("[%s]: %s\n", network_event.type, network_event.content);
null_cnt = 0; // 重置空状态计数器
// STA连接开始事件
if(!strncmp(network_event.content, "STA_CONNECT_STARTING",
strlen("STA_CONNECT_STARTING"))){
tang_ui_net_connecting(); // 更新UI状态
tang_play_key("wifi_linking"); // 播放连接音效
}
// STA连接失败事件
if(!strncmp(network_event.content, "STA_CONNECT_FAILED",
strlen("STA_CONNECT_FAILED"))){
// 提取失败原因
json_object_object_get_ex(wifi_event, "reason", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
printf("STA_CONNECT_FAILED REASON:%s\n", json_object_get_string(tmp));
}
{
tang_ui_net_connect_failed(); // UI更新
tang_play_key("wifi_link_failed"); // 音效反馈
// 切换到下一个网络
new_mode.cmd = SW_STA_NEXT_NET;
new_mode.param.switch_sta.connect_timeout = -1;
if(request_wifi_mode(new_mode) != true)
printf("ERROR: [%s] Request Network Failed, Please Register First!!!!\n", app_name);
}
}
// STA扫描完成事件
if(!strncmp(network_event.content, "STA_SCAN_OVER",
strlen("STA_SCAN_OVER"))){
// 启动网络配置
new_mode.cmd = SW_NETCFG;
new_mode.param.network_config.timeout_ms = -1;
new_mode.param.network_config.method_maps |= NET_CONFIG_METHOD_COOEE;
new_mode.param.network_config.vendor = NET_VENDOR_BROADCOM;
if(request_wifi_mode(new_mode) != true)
printf("ERROR: [%s] Request Network Failed, Please Register First!!!!\n", app_name);
}
}
/*
* 网络配置事件处理 - 配网过程状态变化
* 代码重复:与STA状态处理有相似模式,可抽象共用逻辑
*/
else if (!strncmp(network_event.type, event_type_str[EVENT_TYPE_NET_CFG],
strlen(event_type_str[EVENT_TYPE_NET_CFG]))) {
//printf("[%s]: %s\n", network_event.type, network_event.content);
null_cnt = 0;
// 配网开始
if(!strncmp(network_event.content, net_cfg_status_str[NET_CFG_STATUS_STARTING],
strlen(net_cfg_status_str[NET_CFG_STATUS_STARTING]))) {
tang_ui_net_config(); // UI更新
tang_play_key("airkiss_config"); // 音效反馈
}
// 配网失败
if(!strncmp(network_event.content, net_cfg_status_str[NET_CFG_STATUS_FAILED],
strlen(net_cfg_status_str[NET_CFG_STATUS_FAILED]))) {
tang_ui_net_config_failed(); // UI更新
tang_play_key("airkiss_config_fail"); // 音效反馈
// 提取失败原因
json_object_object_get_ex(wifi_event, "reason", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
printf("NETWORK CONFIGURE REASON:%s\n", json_object_get_string(tmp));
}
// 切换到AP模式进行重新配置
//new_mode.cmd = SW_STA;
new_mode.cmd = SW_AP; // 切换到AP模式
//new_mode.cmd = SW_NETCFG;
if(request_wifi_mode(new_mode) != true)
printf("ERROR: [%s] Request Network Failed, Please Register First!!!!\n", app_name);
}
// 配网成功
else if (!strncmp(network_event.content, net_cfg_status_str[NET_CFG_STATUS_SUCCESS],
strlen(net_cfg_status_str[NET_CFG_STATUS_SUCCESS]))) {
tang_ui_net_config_success(); // UI更新
tang_play_key("airkiss_config_success"); // 音效反馈
{
#if 1 // 条件编译,应该使用更具描述性的宏
// 提取网络配置信息
json_object_object_get_ex(wifi_event, "ssid", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
printf("ssid:%s\n", json_object_get_string(tmp));
}
json_object_object_get_ex(wifi_event, "passwd", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
printf("passwd:%s\n", json_object_get_string(tmp));
}
json_object_object_get_ex(wifi_event, "ip", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
printf("ip:%s\n", json_object_get_string(tmp));
}
#endif
}
}
// 配网取消
else if(!strncmp(network_event.content, net_cfg_status_str[NET_CFG_STATUS_CANCEL],
strlen(net_cfg_status_str[NET_CFG_STATUS_CANCEL]))) {
tang_play_key("airkiss_config_quit"); // 音效反馈
}
}
/*
* WiFi模式变化事件处理 - 主要的工作模式切换逻辑
* 复杂度高:包含大量状态相关的业务逻辑
*/
else if (!strncmp(network_event.type, event_type_str[EVENT_TYPE_WIFI_MODE],
strlen(event_type_str[EVENT_TYPE_WIFI_MODE]))) {
//printf("[%s]: %s\n", network_event.type, network_event.content);
// 提取上一个模式(但未使用,代码质量问题)
json_object_object_get_ex(wifi_event, "last", &tmp);
if(tmp != NULL){
strncpy(test, json_object_get_string(tmp),
strlen(json_object_get_string(tmp)));
//printf("last:%s\n", json_object_get_string(tmp));
}
// 获取当前WiFi模式
wifi_info_t infor = get_wifi_mode();
// 停止相关服务
tang_system("killall ntpd > /dev/null 2>&1");
tang_system("killall dnsmasq > /dev/null 2>&1");
// AP模式处理
if (infor.wifi_mode == WIFI_MODE_AP) {
null_cnt = 0;
tang_ui_net_connect_failed(); // UI状态更新
tang_led_turn_off(LED_RECORD); // LED控制
tang_led_turn_slow_flash(LED_WIFI);
tang_play_key("wifi_ap_mode"); // 音效
#if (SUPPORT_USB_AUDIO == 1)
// USB音频检查
if(tang_usb_audio_is_in() == 0)
#endif
startall(1); // 启动相关服务
}
// STA模式处理 - 最复杂的逻辑分支
else if (infor.wifi_mode == WIFI_MODE_STA) {
tang_ui_net_connected(); // UI更新
null_cnt = 0;
tang_led_turn_off(LED_RECORD);
tang_led_turn_on(LED_WIFI);
tang_play_key("wifi_sta_mode");
// XXX 注释说明需要时间同步
// 1. 同步网络时间(并以CST格式更新系统时间)
// 2. 写入硬件RTC(使用UTC格式)
// 创建时间同步线程
// 性能考虑:每次模式切换都创建线程,可能产生线程创建开销
if (pthread_create(&sync_time_pthread, NULL, sync_time_func, NULL) == -1)
printf("Create sync time pthread failed: %s.\n", strerror(errno));
pthread_detach(sync_time_pthread); // 线程分离,避免资源泄漏
// 启动DNS服务
tang_system("dnsmasq &");
#if (SUPPORT_MULROOM == 1)
// 多房间功能支持
if (mulroom_state != MUL_GROUP_RECEIVER)
startall(1);
if (mulroom_state != MUL_IDLE) {
tang_play_tone_sync(NULL);
/* 在低CPU负载时设置 */
tang_mulroom_restore_mode();
}
#else
#if (SUPPORT_USB_AUDIO == 1)
if(tang_usb_audio_is_in() == 0)
#endif
startall(1); // 启动服务
#endif /* SUPPORT_MULROOM == 1 */
}
// NULL模式处理 - 无连接状态
else if (infor.wifi_mode == WIFI_MODE_NULL) {
null_cnt++;
if(null_cnt >= 10){ // 连续10次空状态后重新配网
null_cnt = 0;
new_mode.cmd = SW_NETCFG;
new_mode.param.network_config.timeout_ms = -1;
new_mode.param.network_config.method_maps |= NET_CONFIG_METHOD_COOEE;
new_mode.param.network_config.vendor = NET_VENDOR_BROADCOM;
if(request_wifi_mode(new_mode) != true)
printf("ERROR: [%s] Request Network Failed, Please Register First!!!!\n", app_name);
}
} else {
printf("[ERROR]: Unknown event type!!!!!!\n");
}
}
/* AP状态事件处理 - 热点模式客户端连接状态 */
else if (!strncmp(network_event.type, event_type_str[EVENT_TYPE_AP_STATUS],
strlen(event_type_str[EVENT_TYPE_AP_STATUS]))) {
//printf("[%s]: %s\n", network_event.type, network_event.content);
if(!strncmp(network_event.content, "AP-STA-CONNECTED",
strlen("AP-STA-CONNECTED"))) {
printf("\nThe client has the connection is successful.\n");
} else if (!strncmp(network_event.content, "AP-STA-DISCONNECTED",
strlen("AP-STA-DISCONNECTED"))) {
printf("\nThe client has been disconnected.\n");
}
}
/* IP地址变化事件 */
else if (!strncmp(network_event.type, event_type_str[EVENT_TYPE_IP_CHANGE],
strlen(event_type_str[EVENT_TYPE_IP_CHANGE]))) {
printf("[WARNING] STA IP ADDR HAS CHANGED!!\n");
}
/* 未知事件处理 */
else {
printf("Unknown Network Events-[%s]: %s\n", network_event.type, network_event.content);
}
// 释放JSON对象 - 良好的资源管理
json_object_put(wifi_event);
return 0;
}
/*
* 条件编译:闹钟功能支持
* 架构设计:使用回调函数模式处理闹钟事件
* 可读性:良好的日志输出,包含完整的闹钟信息
*/
#if (SUPPORT_ALARM == 1)
int alarm_callback(struct alarm_info *a)
{
// 详细的闹钟信息日志
printf("alarm callback id: %d, hour: %d, minute: %d, timestamp: %ld info: %s\n",
a->alarm_id, a->hour, a->minute, a->timestamp, a->prv_info.info);
return 0;
}
#endif
/*
* 初始化函数 - 系统启动时的资源初始化
* 设计模式:模板方法模式 - 定义初始化步骤
* 架构问题:函数职责不够单一,包含多种不同类型的初始化
*/
static int initall(void)
{
// recover volume in S01system_init.sh
// 共享内存初始化 - 进程间通信基础
// 性能:共享内存提供高效的进程间数据共享
if(0 != share_mem_init()){
printf("share_mem_init failure.\n");
}
if(0 != share_mem_clear()){
printf("share_mem_clear failure.\n");
}
// 存储设备状态检测
// 架构:硬件抽象层设计,检测外部存储设备挂载状态
if (tang_path_is_mount("/mnt/sdcard")) {
tfcard_status = 1;
share_mem_set(SDCARD_DOMAIN, STATUS_INSERT); // SD卡插入状态
} else {
share_mem_set(SDCARD_DOMAIN, STATUS_EXTRACT); // SD卡拔出状态
}
// U盘状态检测
if (tang_path_is_mount("/mnt/usb"))
share_mem_set(UDISK_DOMAIN, STATUS_INSERT); // U盘插入
else
share_mem_set(UDISK_DOMAIN, STATUS_EXTRACT); // U盘拔出
// TODO: 各种功能模块初始化 - 代码可读性问题:过多的TODO注释
// shairport init(do not depend network part)
// TODO: render init if needed.
// TODO: localplayer init if needed.
// TODO: bt init if needed.
// TODO: vr init if needed.
// TODO: other init if needed.
return 0;
}
/*
* 内存检查函数 - 已禁用
* 设计模式:调试工具模式
* 性能:在生产环境中被禁用,避免性能开销
*/
#if 0
void check_mem(int line)
{
return ;
pid_t pid = getpid();
time_t timep;
struct tm *p;
FILE *fp;
char rss[8] = {};
char cmd[256] = {};
char path[256] = {};
// get current time.
time(&timep);
p=gmtime(&timep);
printf("capture %d's mem info to %s.\n", pid, path);
// get rss - 获取进程内存使用情况
fp = popen("/bin/ps wl | grep tang | grep -v grep | tr -s ' ' | cut -d' ' -f6", "r");
if (!fp) {
strcpy(rss, "99999");
} else {
fgets(rss, 5, fp);
fclose(fp);
}
// capture exmap info - 内存映射信息捕获
sprintf(path, "/tmp/%06d_%04d%02d%02d_%02d:%02d:%02d_%04d_%s.exmap",
pid, (1900+p->tm_year), (1+p->tm_mon),p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, line, rss);
sprintf(cmd, "echo %d > /proc/exmap; cat /proc/exmap > %s", pid, path);
system(cmd);
sprintf(cmd, "cat /proc/%d/maps >> %s", pid, path);
system(cmd);
}
#endif
/*
* 编译信息输出函数
* 可读性:提供有用的调试信息,便于问题定位
* 架构:系统信息收集工具
*/
static void dump_compile_info(void)
{
time_t timep;
struct passwd *pwd;
char hostname[16] = "Unknown";
// 获取系统信息
time(&timep);
pwd = getpwuid(getuid()); // 获取用户信息
gethostname(hostname, 16); // 获取主机名
// 输出编译环境信息
printf("tang compiled at %s on %s@%s\n", asctime(gmtime(&timep)), pwd->pw_name, hostname);
}
/*
* 版本检查线程函数
* 设计模式:后台工作者线程模式
* 性能:周期性检查,避免频繁的版本检查
* 架构:自动更新机制
*/
void *tang_updater_check_version(void *arg)
{
nvinfo_t *nvinfo = NULL;
// 无限循环检查版本更新
while(1) {
// 检查新版本
if ((nvinfo = tang_updater_chkver()) != NULL) {
free(nvinfo); // 释放版本信息内存
// 启动更新程序
tang_system("updater -p");
break; // 更新后退出线程
}
sleep(10); // 每10秒检查一次
}
return NULL;
}
/*
* 主函数 - 应用程序入口点
* 设计模式:应用程序骨架模式
* 架构:模块化启动,事件驱动架构
*/
int main(int argc, char **argv)
{
int daemonize = 0; // 守护进程标志
// 全局变量初始化
app_name = argv[0]; // 保存应用程序名称
wifi_ctl_msg_t new_mode;
pthread_t updater_chkver_pthread; // 版本检查线程
/* 命令行参数解析 - 使用getopt标准库 */
/* 设计模式:命令行解析器模式 */
int c;
while (1) {
c = getopt(argc, argv, "bBsSh");
if (c < 0)
break;
switch (c) {
case 'b':
case 'B':
daemonize = 1; // 后台运行模式
break;
case 's':
case 'S':
break; // 静默模式?注释不清晰
case 'h':
usage(app_name); // 显示使用帮助
return 0;
default:
usage(app_name);
return 1;
}
}
/* 守护进程化 - 脱离终端在后台运行 */
/* 架构设计:标准的Linux守护进程创建流程 */
if (daemonize) {
if (daemon(0, 1)) { // daemon(nochdir, noclose)
perror("daemon");
return -1;
}
}
// 输出编译信息 - 便于调试和版本管理
dump_compile_info();
/* 多房间功能初始化 */
/* 架构:功能模块的条件编译,支持不同的产品配置 */
#if (SUPPORT_MULROOM == 1)
mulroom_state = tang_mulroom_check_saved_mode(MULROOM_INFO_PATH);
#endif /* SUPPORT_MULROOM == 1 */
/* 本地播放器扫描回调注册 */
/* 设计模式:回调函数模式,异步事件处理 */
#if (SUPPORT_MULROOM == 1)
if (mulroom_state != MUL_GROUP_RECEIVER) {
#if (SUPPORT_LOCALPLAYER == 1)
tang_localplayer_scan_callback(tfcard_scan_1music_callback, tfcard_scan_done_callback);
#endif
}
#else
#if (SUPPORT_LOCALPLAYER == 1)
tang_localplayer_scan_callback(tfcard_scan_1music_callback, tfcard_scan_done_callback);
#endif
#endif /* SUPPORT_MULROOM == 1 */
// 系统初始化
initall();
/* 启动不依赖网络的模块 */
/* 架构设计:分阶段启动,网络相关模块后续启动 */
#if (SUPPORT_MULROOM == 1)
if (mulroom_state != MUL_GROUP_RECEIVER)
startall(0); // 启动所有模块
#else
// start modules do not depend network.
#if (SUPPORT_USB_AUDIO == 1)
if(tang_usb_audio_is_in() == 0)
#endif
startall(0);
#endif /* SUPPORT_MULROOM == 1 */
// 电池容量注册
register_battery_capacity();
/* 事件处理器注册 - 关键架构组件 */
/* 设计模式:观察者模式,事件回调机制 */
// 注册按键事件处理器
keyevent_handler = tang_event_handler_get(keyevent_callback, app_name);
// 注册杂项事件处理器
miscevent_handler = tang_event_handler_get(miscevent_callback, app_name);
/* 网络管理器注册 - 核心网络功能 */
/* 架构:服务注册模式 */
if(register_to_networkmanager(network_callback) != 0) {
printf("ERROR: [%s] register to Network Server Failed!!!!\n", app_name);
} else if(!access("/usr/data/wpa_supplicant.conf", R_OK)) {
// 如果存在WiFi配置文件,自动连接STA模式
memset(&new_mode, 0, sizeof(new_mode));
new_mode.cmd = SW_STA;
new_mode.param.switch_sta.connect_timeout = -1; // 无限超时
if(request_wifi_mode(new_mode) != true)
printf("ERROR: [%s] Request Network Failed, Please Register First!!!!\n", app_name);
}
/* 闹钟功能初始化 */
/* 设计模式:时间事件管理器模式 */
#if (SUPPORT_ALARM == 1)
struct alarm_info *alarm = NULL;
//register alarm manager
register_to_alarm_manager(alarm_callback);
// 检查唤醒状态
if ((alarm = tang_alarm_check_wakeup_status()) != NULL) {
printf("[%s] hour %d minute %d name %s info %s\n",
app_name, alarm->hour, alarm->minute, alarm->name, alarm->prv_info.info);
free(alarm); // 释放闹钟信息内存
}
// 启动闹钟
tang_alarm_start_alarm();
#endif
/* 线路输入检测和处理 */
/* 架构:硬件事件检测和处理 */
#if (SUPPORT_MULROOM == 1)
if (mulroom_state != MUL_GROUP_RECEIVER) {
// process linein insert event on startup.
if (tang_linein_is_in()) {
printf("linein detect, switch to linein mode...\n");
tang_linein_on(); // 切换到线路输入模式
}
}
#else
// process linein insert event on startup.
if (tang_linein_is_in()) {
printf("linein detect, switch to linein mode...\n");
tang_linein_on();
}
#endif /* SUPPORT_MULROOM == 1 */
/* USB音频设备检测 */
#if (SUPPORT_USB_AUDIO == 1)
if(tang_usb_audio_is_in() == 1)
tang_usb_audio_plug_in(); // USB音频设备插入处理
#endif
/* 创建版本检查线程 */
/* 设计模式:后台任务线程模式 */
/* 性能:分离线程,不阻塞主线程 */
if (pthread_create(&updater_chkver_pthread, NULL, tang_updater_check_version, NULL) == -1)
printf("Create updater check version pthread failed: %s.\n", strerror(errno));
pthread_detach(updater_chkver_pthread); // 线程分离,自动回收资源
/* 信号处理设置 - 重要的系统级错误处理 */
/* 架构:信号驱动架构,处理系统事件 */
signal(SIGINT, sig_handler); // 中断信号 (Ctrl+C)
signal(SIGUSR1, sig_handler); // 用户定义信号1
signal(SIGUSR2, sig_handler); // 用户定义信号2
signal(SIGTERM, sig_handler); // 终止信号
signal(SIGBUS, sig_handler); // 总线错误
signal(SIGSEGV, sig_handler); // 段错误
signal(SIGABRT, sig_handler); // 异常终止
signal(SIGPIPE, SIG_IGN); // 忽略管道破裂信号
/* 系统调优 - 内存管理优化 */
/* 性能:设置内存过量使用,提高系统稳定性 */
system("echo 1 > /proc/sys/vm/overcommit_memory");
/* 主事件循环 - 简化的事件循环设计 */
/* 架构:传统的事件循环模式 */
/* 性能问题:使用sleep循环,不是高效的事件驱动 */
while(1) {
sleep(20); // 每20秒执行一次
// 清理页面缓存,提高内存使用效率
system("echo 3 > /proc/sys/vm/drop_caches");
}
return 0;
}